/*
  -----------------------------------------------------------------------------
  This source file is part of OGRE
  (Object-oriented Graphics Rendering Engine)
  For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2014 Torus Knot Software Ltd

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
  -----------------------------------------------------------------------------
*/

#include "PlayPenTests.h"
#include "OgreResourceGroupManager.h"
#include "OgreCodec.h"
#include "OgreFileSystemLayer.h"
#include "OgreMovablePlane.h"
#include "OgreRectangle2D.h"
#include "OgreMovableObject.h"
#include "OgreBillboard.h"
#include "OgreParticleSystem.h"

#ifdef OGRE_BUILD_COMPONENT_MESHLODGENERATOR
#include "OgreLodConfig.h"
#include "OgreMeshLodGenerator.h"
#endif

using namespace Ogre;

struct OrientedLightPtr
{
    Light* l;
    SceneNode* ln;

    OrientedLightPtr(Light* _l) : l(_l)
    {
        ln = l->_getManager()->getRootSceneNode()->createChildSceneNode();
        ln->attachObject(l);
    }

    OrientedLightPtr* operator->() { return this; }

    void setType(Light::LightTypes type) { l->setType(type); }
    void setDirection(const Vector3& v) { ln->setDirection(v, Node::TS_WORLD); }
    void setCastShadows(bool b) { l->setCastShadows(b); }
    void setDiffuseColour(float r, float g, float b) { l->setDiffuseColour(r, g, b); }
    void setSpecularColour(float r, float g, float b) { l->setSpecularColour(r, g, b); }
};

static void createRandomEntityClones(Entity* ent, size_t cloneCount,
    const Vector3& min, const Vector3& max, SceneManager* mgr);

#ifdef OGRE_BUILD_COMPONENT_MESHLODGENERATOR
PlayPen_ManualLOD::PlayPen_ManualLOD()
{
    mInfo["Title"] = "PlayPen_ManualLOD";
    mInfo["Description"] = "Testing meshes with manual LODs assigned";
    addScreenshotFrame(75);
}
//---------------------------------------------------------------------------

void PlayPen_ManualLOD::setupContent()
{
    String meshName = getLODMesh();

    Entity *ent;
    for (int i = 0; i < 5; ++i)
    {
        ent = mSceneMgr->createEntity("robot" + StringConverter::toString(i), meshName);
        // Add entity to the scene node
        SceneNode* n = mSceneMgr->getRootSceneNode()->createChildSceneNode(
            Vector3(0, 0, (i * 50) - (5 * 50 / 2)));
        n->setScale(0.2, 0.2, 0.2);
        n->attachObject(ent);
    }

    mAnimation = ent->getAnimationState("Walk");
    mAnimation->setEnabled(true);

    // Give it a little ambience with lights
    Light* l;
    l = mSceneMgr->createLight("BlueLight");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-200,-80,-100))->attachObject(l);
    l->setDiffuseColour(0.5, 0.5, 1.0);

    l = mSceneMgr->createLight("GreenLight");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,0,-100))->attachObject(l);
    l->setDiffuseColour(0.5, 1.0, 0.5);

    // Position the camera
    mCameraNode->setPosition(100,25,100);
    mCameraNode->lookAt(Vector3(-50, 0, -25), Node::TS_PARENT);

    mSceneMgr->setAmbientLight(ColourValue::White);
}
//---------------------------------------------------------------------------

bool PlayPen_ManualLOD::frameStarted(const FrameEvent& evt)
{
    mAnimation->addTime(evt.timeSinceLastFrame);
    return true;
}
//-----------------------------------------------------------------------

String PlayPen_ManualLOD::getLODMesh()
{
    MeshPtr msh1 = MeshManager::getSingleton().load("robot.mesh", ASSETS_RESOURCE_GROUP);

    LodConfig lodConfig(msh1);
    lodConfig.createManualLodLevel(136, "razor.mesh");
    lodConfig.createManualLodLevel(211, "sphere.mesh");
    MeshLodGenerator().generateLodLevels(lodConfig);

    return msh1->getName();
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

PlayPen_ManualLODFromFile::PlayPen_ManualLODFromFile()
{
    mInfo["Title"] = "PlayPen_ManualLOD_File";
    mInfo["Description"] = "Testing meshes with manual LODs assigned, loaded from a file";
    addScreenshotFrame(75);
}
//---------------------------------------------------------------------

String PlayPen_ManualLODFromFile::getLODMesh()
{
    MeshPtr msh1 = MeshManager::getSingleton().load("robot.mesh", ASSETS_RESOURCE_GROUP);

    LodConfig lodConfig(msh1);
    lodConfig.createManualLodLevel(136, "razor.mesh");
    lodConfig.createManualLodLevel(211, "sphere.mesh");
    MeshLodGenerator().generateLodLevels(lodConfig);

    // this time, we save this data to a file and re-load it

    MeshSerializer ser;
    const ResourceGroupManager::LocationList& ll =
        ResourceGroupManager::getSingleton().getResourceLocationList("Tests");
    String prefix;
    for (auto i : ll)
    {
        if (StringUtil::endsWith(i.archive->getName(), "media"))
        {
            prefix = i.archive->getName();
        }
    }
    ser.exportMesh(msh1.get(), prefix + "/testlod.mesh");

    MeshManager::getSingleton().removeAll();

    return "testlod.mesh";
}
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

PlayPen_ManualBlend::PlayPen_ManualBlend()
{
    mInfo["Title"] = "PlayPen_ManualBlending";
    mInfo["Description"] = "Manual blending";
    addScreenshotFrame(10);
}
//---------------------------------------------------------------------------

void PlayPen_ManualBlend::setupContent()
{
    // create material
    MaterialPtr mat = MaterialManager::getSingleton().create("TestMat",
                                                             TRANSIENT_RESOURCE_GROUP);
    Pass * p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    p->createTextureUnitState("Dirt.jpg");
    TextureUnitState* t = p->createTextureUnitState("ogrelogo.png");
    t->setColourOperationEx(LBX_BLEND_MANUAL, LBS_TEXTURE, LBS_CURRENT,
                            ColourValue::White, ColourValue::White, 0.75);

    Entity *planeEnt = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(planeEnt);
    planeEnt->setMaterialName("TestMat");

    mCameraNode->setPosition(0,0,600);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------

PlayPen_ProjectSphere::PlayPen_ProjectSphere()
{
    mInfo["Title"] = "PlayPen_ProjectSphere";
    mInfo["Description"] = "Projecting a sphere's bounds onto the camera.";
    addScreenshotFrame(10);
}
//---------------------------------------------------------------------------

void PlayPen_ProjectSphere::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue::White);

    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 0;
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            4500,4500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("Examples/GrassFloor");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    mProjectionSphere = new Sphere(Vector3(0, 2000, 0), 1500.0);

    ManualObject* debugSphere = mSceneMgr->createManualObject("debugSphere");
    debugSphere->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_STRIP);

    for (int i = 0; i <= 20; ++i)
    {
        Vector3 basePos(mProjectionSphere->getRadius(), 0, 0);
        Quaternion quat;
        quat.FromAngleAxis(Radian(((float)i/(float)20)*Math::TWO_PI), Vector3::UNIT_Y);
        basePos = quat * basePos;
        debugSphere->position(basePos);
    }
    for (int i = 0; i <= 20; ++i)
    {
        Vector3 basePos(mProjectionSphere->getRadius(), 0, 0);
        Quaternion quat;
        quat.FromAngleAxis(Radian(((float)i/(float)20)*Math::TWO_PI), Vector3::UNIT_Z);
        basePos = quat * basePos;
        debugSphere->position(basePos);
    }

    debugSphere->end();

    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,2000,0))->attachObject(debugSphere);

    MaterialPtr mat = MaterialManager::getSingleton().create(
        "scissormat", TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setDepthWriteEnabled(false);
    p->setSceneBlending(SBT_TRANSPARENT_ALPHA);
    TextureUnitState* t = p->createTextureUnitState();
    t->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT,
                            ColourValue::Red);
    t->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, 0.5f);


    mScissorRect = mSceneMgr->createManualObject("mScissorRect");
    mScissorRect->setUseIdentityProjection(true);
    mScissorRect->setUseIdentityView(true);
    AxisAlignedBox aabb;
    aabb.setInfinite();
    mScissorRect->setBoundingBox(aabb);
    mScissorRect->begin(mat->getName());
    mScissorRect->position(Vector3::ZERO);
    mScissorRect->position(Vector3::ZERO);
    mScissorRect->position(Vector3::ZERO);
    mScissorRect->quad(0, 1, 2, 3);
    mScissorRect->end();
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(mScissorRect);

    mCameraNode->setPosition(0,3000,5000);
    mCameraNode->lookAt(mProjectionSphere->getCenter(), Node::TS_PARENT);

}
//---------------------------------------------------------------------------

bool PlayPen_ProjectSphere::frameStarted(const FrameEvent& evt)
{
    Real left, top, right, bottom;
    mCamera->projectSphere(*mProjectionSphere, &left, &top, &right, &bottom);

    mScissorRect->beginUpdate(0);
    mScissorRect->position(left, top, 0);
    mScissorRect->position(left, bottom, 0);
    mScissorRect->position(right, bottom, 0);
    mScissorRect->position(right, top, 0);
    mScissorRect->quad(0,1,2,3);
    mScissorRect->end();
    return true;
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------

PlayPen_CameraSetDirection::PlayPen_CameraSetDirection()
    : mUseParentNode(false)
    , mUseFixedYaw(true)
    , mFocus(100,200,-300)
{
    mInfo["Title"] = "PlayPen_CameraSetDirection";
    mInfo["Description"] = "Testing various settings for Camera::setDirection";
    addScreenshotFrame(10);
}
//---------------------------------------------------------------------

void PlayPen_CameraSetDirection::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue::White);

    Entity* e = mSceneMgr->createEntity("1", "knot.mesh");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(mFocus)->attachObject(e);


    mCameraNode->setPosition(200,1000,1000);
    mCameraNode->lookAt(mFocus, Node::TS_PARENT);

    //mTrayMgr->createButton(OgreBites::TL_BOTTOM, "Look At", "Look At");
    //mTrayMgr->createCheckBox(OgreBites::TL_BOTTOM, "tglParent", "Use Parent Node");
    //OgreBites::CheckBox* chk = mTrayMgr->createCheckBox(OgreBites::TL_BOTTOM, "tglFixedYaw", "Use Fixed Yaw");
    //chk->setChecked(true, false);
    //mTrayMgr->showCursor();
    //setDragLook(true);

    mParentNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(1000, 2000, -1000));

}
//---------------------------------------------------------------------

void PlayPen_CameraSetDirection::buttonHit(OgreBites::Button* button)
{
    mCameraNode->lookAt(mFocus, Node::TS_PARENT);
}
//---------------------------------------------------------------------

void PlayPen_CameraSetDirection::checkBoxToggled(OgreBites::CheckBox* box)
{
    if (box->getName() == "tglParent")
    {
        mUseParentNode = !mUseParentNode;

        if (mUseParentNode)
            mParentNode->attachObject(mCamera);
        else
            mParentNode->detachAllObjects();
    }
    else if (box->getName() == "tglFixedYaw")
    {
        mUseFixedYaw = !mUseFixedYaw;
        if (mUseFixedYaw)
            mCameraNode->setFixedYawAxis(true);
        else
            mCameraNode->setFixedYawAxis(false);

    }
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------

PlayPen_MorphAnimationWithNormals::PlayPen_MorphAnimationWithNormals()
{
    mInfo["Title"] = "PlayPen_MorphAnimNormals";
    mInfo["Description"] = "Testing morph animation with normals";
    addScreenshotFrame(200);
}
//---------------------------------------------------------------------

void PlayPen_MorphAnimationWithNormals::setupContent()
{
    // explicitly disable stencil volume prep
    MeshManager::getSingleton().setPrepareAllMeshesForShadowVolumes(false);

    // Cannot change this to true, not possible to use software morph
    // animation + normals with stencil shadows because the former
    // requires pos & normals to be in the same buffer, and the latter
    // requires positions to be on their own.  
    // bool testStencil = false;

    //if (testStencil)
    //  mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_MODULATIVE);

    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
    Vector3 dir(-1, -1, 0.5);
    dir.normalise();
    OrientedLightPtr l = mSceneMgr->createLight("light1");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(dir);

    MeshPtr mesh = MeshManager::getSingleton().load("sphere.mesh", ASSETS_RESOURCE_GROUP);

    String morphName = "testmorphwithnormals.mesh";
    mesh = mesh->clone(morphName);

    SubMesh* sm = mesh->getSubMesh(0);
    // Re-organise geometry since this mesh has no animation and all
    // vertex elements are packed into one buffer
    VertexDeclaration* newDecl =
        sm->vertexData->vertexDeclaration->getAutoOrganisedDeclaration(false, true, true);
    sm->vertexData->reorganiseBuffers(newDecl);
    //if (testStencil)
    //  sm->vertexData->prepareForShadowVolume(); // need to re-prep since reorganised
    // get the position buffer (which should now be separate);
    const VertexElement* posElem =
        sm->vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
    HardwareVertexBufferSharedPtr origbuf =
        sm->vertexData->vertexBufferBinding->getBuffer(
            posElem->getSource());

    // Create a new position & normal buffer with updated values
    HardwareVertexBufferSharedPtr newbuf =
        HardwareBufferManager::getSingleton().createVertexBuffer(
            VertexElement::getTypeSize(VET_FLOAT3) * 2,
            sm->vertexData->vertexCount,
            HardwareBuffer::HBU_STATIC, true);
    float* pSrc = static_cast<float*>(origbuf->lock(HardwareBuffer::HBL_READ_ONLY));
    float* pDst = static_cast<float*>(newbuf->lock(HardwareBuffer::HBL_DISCARD));

    // Make the sphere turn into a cube
    // Do this just by clamping each of the directions (we shrink it)
    float cubeDimension = 0.3f * mesh->getBoundingSphereRadius();
    size_t srcSkip = origbuf->getVertexSize() / sizeof(float) - 3;
    for (size_t v = 0; v < sm->vertexData->vertexCount; ++v)
    {
        // x/y/z position
        Vector3 pos;
        for (int d = 0; d < 3; ++d)
        {
            if (*pSrc >= 0)
            {
                pos.ptr()[d] = std::min(cubeDimension, *pSrc++);
            }
            else
            {
                pos.ptr()[d] = std::max(-cubeDimension, *pSrc++);
            }
            *pDst++ = pos.ptr()[d];
        }

        // normal
        // this should point along the major axis
        // unfortunately since vertices are not duplicated at edges there will be
        // some inaccuracy here but the most important thing is to add sharp edges
        Vector3 norm = pos.normalisedCopy();
        norm = norm.primaryAxis();
        *pDst++ = norm.x;
        *pDst++ = norm.y;
        *pDst++ = norm.z;

        pSrc += srcSkip;

    }

    origbuf->unlock();
    newbuf->unlock();

    // create a morph animation
    Animation* anim = mesh->createAnimation("testAnim", 10.0f);
    VertexAnimationTrack* vt = anim->createVertexTrack(1, sm->vertexData, VAT_MORPH);
    // re-use start positions for frame 0
    VertexMorphKeyFrame* kf = vt->createVertexMorphKeyFrame(0);
    kf->setVertexBuffer(origbuf);

    // Use translated buffer for mid frame
    kf = vt->createVertexMorphKeyFrame(4.0f);
    kf->setVertexBuffer(newbuf);

    // Pause there
    kf = vt->createVertexMorphKeyFrame(6.0f);
    kf->setVertexBuffer(newbuf);

    // re-use start positions for final frame
    kf = vt->createVertexMorphKeyFrame(10.0f);
    kf->setVertexBuffer(origbuf);

    // Export the mesh
    String outPath, baseName;
    String exportName = mContext->getFSLayer().getWritablePath(morphName);
    StringUtil::splitFilename(exportName, baseName, outPath);
    Ogre::ResourceGroupManager& resMgr = Ogre::ResourceGroupManager::getSingleton();
    resMgr.addResourceLocation(outPath, "FileSystem", TRANSIENT_RESOURCE_GROUP, false, false);

    DataStreamPtr stream = resMgr.createResource(morphName, TRANSIENT_RESOURCE_GROUP);
    MeshSerializer ser;
    ser.exportMesh(mesh.get(), stream);
    stream->close();

    // Unload old mesh to force reload
    MeshManager::getSingleton().remove(mesh->getHandle());
    mesh->unload();
    mesh.reset();

    Entity* e = mSceneMgr->createEntity("test", morphName);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);
    AnimationState* animState = e->getAnimationState("testAnim");
    animState->setEnabled(true);
    animState->setWeight(1.0f);
    mAnimations[0] = animState;

    e = mSceneMgr->createEntity("test2", morphName);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(200,0,0))->attachObject(e);
    // test hardware morph
    e->setMaterialName("Examples/HardwareMorphAnimationWithNormals");
    animState = e->getAnimationState("testAnim");
    animState->setEnabled(true);
    animState->setWeight(1.0f);
    mAnimations[1] = animState;

    resMgr.deleteResource(morphName, TRANSIENT_RESOURCE_GROUP);

    mCamera->setNearClipDistance(0.5);
    mCameraNode->setPosition(0,100,-400);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);
    //mSceneMgr->setShowDebugShadows(true);

    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 200;
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            1500,1500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);
}

bool PlayPen_MorphAnimationWithNormals::frameStarted(const FrameEvent& evt)
{
    mAnimations[0]->addTime(evt.timeSinceLastFrame);
    mAnimations[1]->addTime(evt.timeSinceLastFrame);
    return true;
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------

PlayPen_MorphAnimationWithoutNormals::PlayPen_MorphAnimationWithoutNormals()
{
    mInfo["Title"] = "PlayPen_MorphAnimNoNormals";
    mInfo["Description"] = "Testing morph animation without normals";
    addScreenshotFrame(200);
}
//---------------------------------------------------------------------

void PlayPen_MorphAnimationWithoutNormals::setupContent()
{
    //bool testStencil = false;

    //if (testStencil)
    //    mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_MODULATIVE);

    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
    Vector3 dir(-1, -1, 0.5);
    dir.normalise();
    OrientedLightPtr l = mSceneMgr->createLight("light1");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(dir);


    MeshPtr mesh = MeshManager::getSingleton().load("sphere.mesh",
                                                    ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

    String morphName = "testmorphnonormals.mesh";
    mesh = mesh->clone(morphName);

    SubMesh* sm = mesh->getSubMesh(0);
    // Re-organise geometry since this mesh has no animation and all
    // vertex elements are packed into one buffer
    VertexDeclaration* newDecl =
        sm->vertexData->vertexDeclaration->getAutoOrganisedDeclaration(false, true, false);
    sm->vertexData->reorganiseBuffers(newDecl);
    //if (testStencil)
    //    sm->vertexData->prepareForShadowVolume(); // need to re-prep since reorganised
    // get the position buffer (which should now be separate);
    const VertexElement* posElem =
        sm->vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
    HardwareVertexBufferSharedPtr origbuf =
        sm->vertexData->vertexBufferBinding->getBuffer(
            posElem->getSource());

    // Create a new position & normal buffer with updated values
    HardwareVertexBufferSharedPtr newbuf =
        HardwareBufferManager::getSingleton().createVertexBuffer(
            VertexElement::getTypeSize(VET_FLOAT3),
            sm->vertexData->vertexCount,
            HardwareBuffer::HBU_STATIC, true);
    float* pSrc = static_cast<float*>(origbuf->lock(HardwareBuffer::HBL_READ_ONLY));
    float* pDst = static_cast<float*>(newbuf->lock(HardwareBuffer::HBL_DISCARD));

    // Make the sphere turn into a cube
    // Do this just by clamping each of the directions (we shrink it)
    float cubeDimension = 0.3f * mesh->getBoundingSphereRadius();
    for (size_t v = 0; v < sm->vertexData->vertexCount; ++v)
    {
        // x/y/z position
        Vector3 pos;
        for (int d = 0; d < 3; ++d)
        {
            if (*pSrc >= 0)
            {
                pos.ptr()[d] = std::min(cubeDimension, *pSrc++);
            }
            else
            {
                pos.ptr()[d] = std::max(-cubeDimension, *pSrc++);
            }
            *pDst++ = pos.ptr()[d];
        }

    }

    origbuf->unlock();
    newbuf->unlock();

    // create a morph animation
    Animation* anim = mesh->createAnimation("testAnim", 10.0f);
    VertexAnimationTrack* vt = anim->createVertexTrack(1, sm->vertexData, VAT_MORPH);
    // re-use start positions for frame 0
    VertexMorphKeyFrame* kf = vt->createVertexMorphKeyFrame(0);
    kf->setVertexBuffer(origbuf);

    // Use translated buffer for mid frame
    kf = vt->createVertexMorphKeyFrame(4.0f);
    kf->setVertexBuffer(newbuf);

    // Pause there
    kf = vt->createVertexMorphKeyFrame(6.0f);
    kf->setVertexBuffer(newbuf);

    // re-use start positions for final frame
    kf = vt->createVertexMorphKeyFrame(10.0f);
    kf->setVertexBuffer(origbuf);

    // Add resource location for exported mesh
    String exportName = mContext->getFSLayer().getWritablePath(morphName);
    String path;
    StringUtil::splitFilename(exportName, morphName, path);
    ResourceGroupManager::getSingleton().addResourceLocation(path, "FileSystem", TRANSIENT_RESOURCE_GROUP, false, false);

    // Export the mesh
    DataStreamPtr stream = ResourceGroupManager::getSingleton().createResource(morphName, TRANSIENT_RESOURCE_GROUP);
    MeshSerializer ser;
    ser.exportMesh(mesh.get(), stream);
    stream->close();


    // Unload old mesh to force reload
    MeshManager::getSingleton().remove(mesh->getHandle());
    mesh->unload();
    mesh.reset();

    Entity* e = mSceneMgr->createEntity("test", morphName);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);
    AnimationState* animState = e->getAnimationState("testAnim");
    animState->setEnabled(true);
    animState->setWeight(1.0f);
    mAnimations[0] = animState;

    e = mSceneMgr->createEntity("test2", morphName);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(200,0,0))->attachObject(e);
    // test hardware morph
    e->setMaterialName("Examples/HardwareMorphAnimation");
    animState = e->getAnimationState("testAnim");
    animState->setEnabled(true);
    animState->setWeight(1.0f);
    mAnimations[1] = animState;

    ResourceGroupManager::getSingleton().deleteResource(morphName, TRANSIENT_RESOURCE_GROUP);

    mCamera->setNearClipDistance(0.5);
    mCameraNode->setPosition(0,100,-400);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);
    // mSceneMgr->setShowDebugShadows(true);

    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 200;
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            1500,1500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

}

bool PlayPen_MorphAnimationWithoutNormals::frameStarted(const FrameEvent& evt)
{
    mAnimations[0]->addTime(evt.timeSinceLastFrame);
    mAnimations[1]->addTime(evt.timeSinceLastFrame);
    return true;
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------

PlayPen_PoseAnimationWithNormals::PlayPen_PoseAnimationWithNormals()
{
    mInfo["Title"] = "PlayPen_PoseAnimNormals";
    mInfo["Description"] = "Testing pose animation with normals";
    addScreenshotFrame(200);
}
//---------------------------------------------------------------------

void PlayPen_PoseAnimationWithNormals::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
    Vector3 dir(-1, -1, 0.5);
    dir.normalise();
    OrientedLightPtr l = mSceneMgr->createLight("light1");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(dir);

    MeshPtr mesh = MeshManager::getSingleton().load("cube.mesh", ASSETS_RESOURCE_GROUP);

    String newName = "testposewithnormals.mesh";
    mesh = mesh->clone(newName);


    SubMesh* sm = mesh->getSubMesh(0);
    // Re-organise geometry since this mesh has no animation and all
    // vertex elements are packed into one buffer
    VertexDeclaration* newDecl =
        sm->vertexData->vertexDeclaration->getAutoOrganisedDeclaration(false, true, true);
    sm->vertexData->reorganiseBuffers(newDecl);

    // create 2 poses
    Pose* pose = mesh->createPose(1, "pose1");
    // Pose1 moves vertices 0, 1, 2 and 3 upward and pushes normals left
    Vector3f offset1(0, 50, 0);
    pose->addVertex(0, offset1, Vector3f(-1, 0, 0));
    pose->addVertex(1, offset1, Vector3f(-1, 0, 0));
    pose->addVertex(2, offset1, Vector3f(-1, 0, 0));
    pose->addVertex(3, offset1, Vector3f(-1, 0, 0));

    pose = mesh->createPose(1, "pose2");
    // Pose2 moves vertices 3, 4, and 5 to the right and pushes normals right
    // Note 3 gets affected by both
    Vector3f offset2(100, 0, 0);
    pose->addVertex(3, offset2, Vector3f(1, 0, 0));
    pose->addVertex(4, offset2, Vector3f(1, 0, 0));
    pose->addVertex(5, offset2, Vector3f(1, 0, 0));


    Animation* anim = mesh->createAnimation("poseanim", 20.0f);
    VertexAnimationTrack* vt = anim->createVertexTrack(1, sm->vertexData, VAT_POSE);

    // Frame 0 - no effect
    vt->createVertexPoseKeyFrame(0);

    // Frame 1 - bring in pose 1 (index 0)
    VertexPoseKeyFrame* kf = vt->createVertexPoseKeyFrame(3);
    kf->addPoseReference(0, 1.0f);

    // Frame 2 - remove all
    vt->createVertexPoseKeyFrame(6);

    // Frame 3 - bring in pose 2 (index 1)
    kf = vt->createVertexPoseKeyFrame(9);
    kf->addPoseReference(1, 1.0f);

    // Frame 4 - remove all
    vt->createVertexPoseKeyFrame(12);


    // Frame 5 - bring in pose 1 at 50%, pose 2 at 100%
    kf = vt->createVertexPoseKeyFrame(15);
    kf->addPoseReference(0, 0.5f);
    kf->addPoseReference(1, 1.0f);

    // Frame 6 - bring in pose 1 at 100%, pose 2 at 50%
    kf = vt->createVertexPoseKeyFrame(18);
    kf->addPoseReference(0, 1.0f);
    kf->addPoseReference(1, 0.5f);

    // Frame 7 - reset
    vt->createVertexPoseKeyFrame(20);


    // Export the mesh
    String exportName = mContext->getFSLayer().getWritablePath(newName);
    String outPath, baseName;
    StringUtil::splitFilename(exportName, baseName, outPath);
    Ogre::ResourceGroupManager& resMgr = Ogre::ResourceGroupManager::getSingleton();
    resMgr.addResourceLocation(outPath, "FileSystem", TRANSIENT_RESOURCE_GROUP, false, false);
    DataStreamPtr stream = resMgr.createResource(newName, TRANSIENT_RESOURCE_GROUP);
    MeshSerializer ser;
    ser.exportMesh(mesh.get(), stream);
    stream->close();

    // Unload old mesh to force reload
    MeshManager::getSingleton().remove(mesh->getHandle());
    mesh->unload();
    mesh.reset();

    Entity*  e;
    AnimationState* animState;
    // software pose
    e = mSceneMgr->createEntity("test2", newName);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(150,0,0))->attachObject(e);
    animState = e->getAnimationState("poseanim");
    animState->setEnabled(true);
    animState->setWeight(1.0f);
    mAnimations[0] = animState;

    // test hardware pose
    e = mSceneMgr->createEntity("test", newName);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);
    e->setMaterialName("Examples/HardwarePoseAnimationWithNormals");
    animState = e->getAnimationState("poseanim");
    animState->setEnabled(true);
    animState->setWeight(1.0f);
    mAnimations[1] = animState;

    resMgr.deleteResource(newName, TRANSIENT_RESOURCE_GROUP);

    mCamera->setNearClipDistance(0.5);
    mSceneMgr->setShowDebugShadows(true);

    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 200;
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            1500,1500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    mCameraNode->setPosition(0,-200,-300);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);

}
//---------------------------------------------------------------------

bool PlayPen_PoseAnimationWithNormals::frameStarted(const FrameEvent& evt)
{
    mAnimations[0]->addTime(evt.timeSinceLastFrame);
    mAnimations[1]->addTime(evt.timeSinceLastFrame);
    return true;
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------

PlayPen_PoseAnimationWithoutNormals::PlayPen_PoseAnimationWithoutNormals()
{
    mInfo["Title"] = "PlayPen_PoseAnimNoNormals";
    mInfo["Description"] = "Testing pose animation without normals";
    addScreenshotFrame(200);
}
//---------------------------------------------------------------------

void PlayPen_PoseAnimationWithoutNormals::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
    Vector3 dir(-1, -1, 0.5);
    dir.normalise();
    OrientedLightPtr l = mSceneMgr->createLight("light1");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(dir);

    MeshPtr mesh = MeshManager::getSingleton().load("cube.mesh", ASSETS_RESOURCE_GROUP);

    String newName = "testposenonormals.mesh";
    mesh = mesh->clone(newName);


    SubMesh* sm = mesh->getSubMesh(0);
    // Re-organise geometry since this mesh has no animation and all
    // vertex elements are packed into one buffer
    VertexDeclaration* newDecl =
        sm->vertexData->vertexDeclaration->getAutoOrganisedDeclaration(false, true, false);
    sm->vertexData->reorganiseBuffers(newDecl);

    // create 2 poses
    Pose* pose = mesh->createPose(1, "pose1");
    // Pose1 moves vertices 0, 1, 2 and 3 upward
    Vector3f offset1(0, 50, 0);
    pose->addVertex(0, offset1);
    pose->addVertex(1, offset1);
    pose->addVertex(2, offset1);
    pose->addVertex(3, offset1);

    pose = mesh->createPose(1, "pose2");
    // Pose2 moves vertices 3, 4, and 5 to the right
    // Note 3 gets affected by both
    Vector3f offset2(100, 0, 0);
    pose->addVertex(3, offset2);
    pose->addVertex(4, offset2);
    pose->addVertex(5, offset2);


    Animation* anim = mesh->createAnimation("poseanim", 20.0f);
    VertexAnimationTrack* vt = anim->createVertexTrack(1, sm->vertexData, VAT_POSE);

    // Frame 0 - no effect
    vt->createVertexPoseKeyFrame(0);

    // Frame 1 - bring in pose 1 (index 0)
    VertexPoseKeyFrame* kf = vt->createVertexPoseKeyFrame(3);
    kf->addPoseReference(0, 1.0f);

    // Frame 2 - remove all
    vt->createVertexPoseKeyFrame(6);

    // Frame 3 - bring in pose 2 (index 1)
    kf = vt->createVertexPoseKeyFrame(9);
    kf->addPoseReference(1, 1.0f);

    // Frame 4 - remove all
    vt->createVertexPoseKeyFrame(12);


    // Frame 5 - bring in pose 1 at 50%, pose 2 at 100%
    kf = vt->createVertexPoseKeyFrame(15);
    kf->addPoseReference(0, 0.5f);
    kf->addPoseReference(1, 1.0f);

    // Frame 6 - bring in pose 1 at 100%, pose 2 at 50%
    kf = vt->createVertexPoseKeyFrame(18);
    kf->addPoseReference(0, 1.0f);
    kf->addPoseReference(1, 0.5f);

    // Frame 7 - reset
    vt->createVertexPoseKeyFrame(20);

    // Export the mesh
    String outPath, baseName;
    String exportName = mContext->getFSLayer().getWritablePath(newName);
    StringUtil::splitFilename(exportName, baseName, outPath);
    Ogre::ResourceGroupManager& resMgr = Ogre::ResourceGroupManager::getSingleton();
    resMgr.addResourceLocation(outPath, "FileSystem", TRANSIENT_RESOURCE_GROUP, false, false);

    DataStreamPtr stream = resMgr.createResource(newName, TRANSIENT_RESOURCE_GROUP);
    MeshSerializer ser;
    ser.exportMesh(mesh.get(), stream);
    stream->close();

    // Unload old mesh to force reload
    MeshManager::getSingleton().remove(mesh->getHandle());
    mesh->unload();
    mesh.reset();

    Entity*  e;
    AnimationState* animState;
    // software pose
    e = mSceneMgr->createEntity("test2", newName);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(150,0,0))->attachObject(e);
    animState = e->getAnimationState("poseanim");
    animState->setEnabled(true);
    animState->setWeight(1.0f);
    mAnimations[0] = animState;

    // test hardware pose
    e = mSceneMgr->createEntity("test", newName);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);
    e->setMaterialName("Examples/HardwarePoseAnimation");
    animState = e->getAnimationState("poseanim");
    animState->setEnabled(true);
    animState->setWeight(1.0f);
    mAnimations[1] = animState;

    resMgr.deleteResource(newName, TRANSIENT_RESOURCE_GROUP);

    mCamera->setNearClipDistance(0.5);

    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 200;
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            1500,1500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    mCameraNode->setPosition(0,-200,-300);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);
}
//---------------------------------------------------------------------------

bool PlayPen_PoseAnimationWithoutNormals::frameStarted(const FrameEvent& evt)
{
    mAnimations[0]->addTime(evt.timeSinceLastFrame);
    mAnimations[1]->addTime(evt.timeSinceLastFrame);
    return true;
}
//---------------------------------------------------------------------------

PlayPen_SceneNodeTracking::PlayPen_SceneNodeTracking()
{
    mInfo["Title"] = "PlayPen_SceneNodeTracking";
    mInfo["Description"] = "Testing scenenode tracking.";
    addScreenshotFrame(200);
}
//-----------------------------------------------------------------------

bool PlayPen_SceneNodeTracking::frameStarted(const FrameEvent& evt)
{
    mAnimState->addTime(evt.timeSinceLastFrame);
    return true;
}
//-----------------------------------------------------------------------

void PlayPen_SceneNodeTracking::setupContent()
{
    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.2, 0.2, 0.2));

    // Create a skydome
    mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);

    // Create a light
    Light* l = mSceneMgr->createLight("MainLight");
    // Accept default settings: point light, white diffuse, just set position
    // NB I could attach the light to a SceneNode if I wanted it to move automatically with
    //  other objects, but I don't
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(20,80,50))->attachObject(l);

    Entity *ent;

    // Define a floor plane mesh
    Plane p;
    p.normal = Vector3::UNIT_Y;
    p.d = 200;
    MeshManager::getSingleton().createPlane("FloorPlane",
                                            TRANSIENT_RESOURCE_GROUP,
                                            p,200000,200000,20,20,true,1,50,50,Vector3::UNIT_Z);

    // Create an entity (the floor)
    ent = mSceneMgr->createEntity("floor", "FloorPlane");
    ent->setMaterialName("Examples/RustySteel");
    // Attach to child of root node, better for culling (otherwise bounds are the combination of the 2)
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);

    // Add a head, give it it's own node
    SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    ent = mSceneMgr->createEntity("head", "ogrehead.mesh");
    headNode->attachObject(ent);

    // Add another head, give it it's own node
    SceneNode* headNode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    ent = mSceneMgr->createEntity("head2", "ogrehead.mesh");
    headNode2->attachObject(ent);

    // Make sure the head node tracks the root
    headNode->setAutoTracking(true, headNode2, Vector3::UNIT_Z);
    //headNode->setFixedYawAxis(true);

    // Create the camera node & attach camera
    //SceneNode* camNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    //camNode->attachObject(mCamera);

    // set up spline animation of node
    Animation* anim = mSceneMgr->createAnimation("CameraTrack", 10);
    // Spline it for nice curves
    anim->setInterpolationMode(Animation::IM_SPLINE);
    // Create a track to animate the head's node
    NodeAnimationTrack* track = anim->createNodeTrack(0, headNode);
    // Setup keyframes
    track->createNodeKeyFrame(0); // startposition
    TransformKeyFrame* key = track->createNodeKeyFrame(2.5);
    key->setTranslate(Vector3(500,500,-1000));
    key = track->createNodeKeyFrame(5);
    key->setTranslate(Vector3(-1500,1000,-600));
    key = track->createNodeKeyFrame(7.5);
    key->setTranslate(Vector3(0,-100,0));
    key = track->createNodeKeyFrame(10);
    key->setTranslate(Vector3(0,0,0));
    // Create a track to animate the second head's node
    track = anim->createNodeTrack(1, headNode2);
    // Setup keyframes
    track->createNodeKeyFrame(0); // startposition
    key = track->createNodeKeyFrame(2.5);
    key->setTranslate(Vector3(-500,600,-100));
    key = track->createNodeKeyFrame(5);
    key->setTranslate(Vector3(800,200,-600));
    key = track->createNodeKeyFrame(7.5);
    key->setTranslate(Vector3(200,-1000,0));
    key = track->createNodeKeyFrame(10);
    key->setTranslate(Vector3(30,70,110));
    // Create a new animation state to track this
    mAnimState = mSceneMgr->createAnimationState("CameraTrack");
    mAnimState->setEnabled(true);

    // Put in a bit of fog for the hell of it
    //mSceneMgr->setFog(FOG_EXP, ColourValue::White, 0.0002);

    mCameraNode->setPosition(-300,600,2000);
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
PlayPen_NonUniqueResourceNames::PlayPen_NonUniqueResourceNames()
{
    mInfo["Title"] = "PlayPen_NonUniqueResourceNames";
    mInfo["Description"] = "Testing resources without unique names (in different resource groups).";
    addScreenshotFrame(50);
}
//-----------------------------------------------------------------------

void PlayPen_NonUniqueResourceNames::setupContent()
{
    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

    // Define the required skyplane
    Plane plane;
    // 5000 world units from the camera
    plane.d = 5000;
    // Above the camera, facing down
    plane.normal = -Vector3::UNIT_Y;
    // Create the plane 10000 units wide, tile the texture 3 times
    mSceneMgr->setSkyPlane(true, plane, "Examples/SpaceSkyPlane",10000,3);

    // Create a light
    Light* l = mSceneMgr->createLight("MainLight");
    // Accept default settings: point light, white diffuse, just set position
    // NB I could attach the light to a SceneNode if I wanted it to move automatically with
    //  other objects, but I don't
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(20,80,50))->attachObject(l);

    createMeshEntity("Model1", Vector3(10, 10, 10));
    createMeshEntity("Model2", Vector3(-10, -10, -10));

    mCameraNode->setPosition(100,0,-100);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);
}
//-----------------------------------------------------------------------

void PlayPen_NonUniqueResourceNames::createMeshEntity(const String& group, Vector3 pos)
{
    // Get path to test resources (ugly, but the only way I can think
    // of to consistently get the right path (since it's determined by
    // cmake build location) without explicitly defining the groups in
    // resources.cfg).
    const Ogre::ResourceGroupManager::LocationList& ll = Ogre::ResourceGroupManager::getSingleton().getResourceLocationList("Tests");
    const Ogre::ResourceGroupManager::ResourceLocation* loc = &ll.front();
    Ogre::String testResourcePath = loc->archive->getName();

    Ogre::String meshFilePath = testResourcePath + "/" + group;

    Ogre::ResourceGroupManager& resMgr = Ogre::ResourceGroupManager::getSingleton();
       resMgr.createResourceGroup(group, false);
    resMgr.addResourceLocation(meshFilePath, "FileSystem", group);
    resMgr.initialiseResourceGroup(group);

    Ogre::MeshPtr newMesh = Ogre::MeshManager::getSingleton().load("UniqueModel.MESH", group);
    Entity *newEnt = mSceneMgr->createEntity(group, "UniqueModel.MESH", group);
    
    SceneNode* newNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    newNode->attachObject(newEnt);
    newNode->setPosition(pos);

    // I was getting an assertion on some part of the skeleton loading
    //AnimationState* aniState =newEnt->getAnimationState(newEnt->getMesh()->getSkeleton()->getAnimation(0)->getName());
    //mAnimStateList.push_back(aniState);
    //aniState->setEnabled(true);
    //aniState->setLoop(true);
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------

PlayPen_16Textures::PlayPen_16Textures()
{
    mInfo["Title"] = "PlayPen_16Textures";
    mInfo["Description"] = "Tests applying 16 textures in a single material.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_16Textures::testCapabilities(const Ogre::RenderSystemCapabilities* caps) {
    if(caps->getNumTextureUnits() < 16)
        throw Ogre::Exception(999, "Needs 16 Texture Units to run", "testCapabilities");
}

void PlayPen_16Textures::setupContent()
{
    const char* lang = "";
    if(GpuProgramManager::getSingleton().isSyntaxSupported("glsles"))
        lang = "glsles";
    else if (GpuProgramManager::getSingleton().isSyntaxSupported("glsl"))
        lang = "glsl";
    else // DirectX
        lang = "hlsl";

    auto frag = HighLevelGpuProgramManager::getSingleton().createProgram("frag16", TRANSIENT_RESOURCE_GROUP,
                                                                    lang, GPT_FRAGMENT_PROGRAM);
    frag->setSource("#include <OgreUnifiedShader.h> \n\
                    SAMPLER2D(tex0, 0); \
                    SAMPLER2D(tex1, 1); \
                    SAMPLER2D(tex2, 2); \
                    SAMPLER2D(tex3, 3); \
                    SAMPLER2D(tex4, 4); \
                    SAMPLER2D(tex5, 5); \
                    SAMPLER2D(tex6, 6); \
                    SAMPLER2D(tex7, 7); \
                    SAMPLER2D(tex8, 8); \
                    SAMPLER2D(tex9, 9); \
                    SAMPLER2D(tex10, 10); \
                    SAMPLER2D(tex11, 11); \
                    SAMPLER2D(tex12, 12); \
                    SAMPLER2D(tex13, 13); \
                    SAMPLER2D(tex14, 14); \
                    SAMPLER2D(tex15, 15); \
                    MAIN_PARAMETERS \
                    IN(vec4 ambientUV, TEXCOORD0) \
                    MAIN_DECLARATION \
                    { \
                    gl_FragColor = texture2D(tex15, ambientUV.xy); \
                    } \
                    ");

    MaterialPtr mat = MaterialManager::getSingleton().create("test16", TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setVertexProgram("Ogre/BasicVertexPrograms/AmbientOneTextureWithUV");
    p->setGpuProgram(GPT_FRAGMENT_PROGRAM, frag);
    // create 15 textures the same
    for (int i = 0; i < 15; ++i)
    {
        p->createTextureUnitState("Dirt.jpg");
    }
    // create 16th texture differently
    p->createTextureUnitState("ogrelogo.png");
    if (StringUtil::startsWith(frag->getSyntaxCode(), "glsl"))
    {
        // map samplers
        GpuProgramParametersSharedPtr params = p->getFragmentProgramParameters();
        params->setIgnoreMissingParams(true);
        for (int i = 0; i < 16; ++i)
        {
            params->setNamedConstant(String("tex") + StringConverter::toString(i), i);
        }
    }

    Entity* e = mSceneMgr->createEntity("1", "knot.mesh");
    e->setMaterial(mat);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);

    mCameraNode->setPosition(0,0,250);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);


}

//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_2Spotlights::PlayPen_2Spotlights()
{
    mInfo["Title"] = "PlayPen_2Spotlights";
    mInfo["Description"] = "Tests 2 spotlights on one mesh.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_2Spotlights::setupContent()
{
    SceneNode* mTestNode[5];
    mSceneMgr->setAmbientLight(ColourValue(0.3, 0.3, 0.3));

    Light* mLight = mSceneMgr->createLight("MainLight");
    // Spotlight test
    mLight->setType(Light::LT_SPOTLIGHT);
    mLight->setDiffuseColour(1.0, 0.0, 0.8);
    mLight->setSpotlightRange(Degree(30), Degree(40));
    mTestNode[0] = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    mTestNode[0]->setPosition(800,600,0);
    mTestNode[0]->lookAt(Vector3(800,0,0), Node::TS_WORLD);
    mTestNode[0]->attachObject(mLight);

    mTestNode[1] = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    mLight = mSceneMgr->createLight("AnotherLight");
    // Spotlight test
    mLight->setType(Light::LT_SPOTLIGHT);
    mLight->setDiffuseColour(0, 1.0, 0.8);
    mLight->setSpotlightRange(Degree(30), Degree(40));
    mTestNode[1] = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    mTestNode[1]->setPosition(0,600,800);
    mTestNode[1]->lookAt(Vector3(0,0,800), Node::TS_WORLD);
    mTestNode[1]->attachObject(mLight);

    Plane plane( Vector3::UNIT_Y, -100);
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            3500,3500,100,100,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt;
    pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    mCameraNode->setPosition(-600,300,-600);
    mCameraNode->lookAt(Vector3(300, 0, 300), Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_AlphaToCoverage::PlayPen_AlphaToCoverage()
{
    mInfo["Title"] = "PlayPen_AlphaToCoverage";
    mInfo["Description"] = "Tests alpha to coverage support.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_AlphaToCoverage::setupContent()
{

    MaterialPtr mat = MaterialManager::getSingleton().create(
        "testa2c",
        TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setAlphaRejectSettings(CMPF_GREATER, 96);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    p->setAlphaToCoverageEnabled(true);
    TextureUnitState* t = p->createTextureUnitState("leaf.png");
    t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
    t->setColourOperation(LBO_ALPHA_BLEND);
    Entity *e = mSceneMgr->createEntity("PlaneA2C", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(100, 0, 0))->attachObject(e);


    mat = MaterialManager::getSingleton().create(
        "testnoa2c",
        TRANSIENT_RESOURCE_GROUP);
    p = mat->getTechnique(0)->getPass(0);
    p->setAlphaRejectSettings(CMPF_GREATER, 96);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    p->setAlphaToCoverageEnabled(false);
    t = p->createTextureUnitState("leaf.png");
    t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
    t->setColourOperation(LBO_ALPHA_BLEND);
    e = mSceneMgr->createEntity("PlaneNoA2C", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-100, 0, 0))->attachObject(e);

    mat = MaterialManager::getSingleton().create(
        "bg",
        TRANSIENT_RESOURCE_GROUP);
    p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    t = p->createTextureUnitState();
    t->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, ColourValue::White);
    e = mSceneMgr->createEntity("PlaneBg", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    e->setRenderQueueGroup(RENDER_QUEUE_BACKGROUND);
    SceneNode* s = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0, 0, -10));
    s->setScale(5,5,5);
    s->attachObject(e);

    mCameraNode->setPosition(0,0,300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_AttachObjectsToBones::PlayPen_AttachObjectsToBones()
{
    mInfo["Title"] = "PlayPen_AttachObjectsToBones";
    mInfo["Description"] = "Tests attaching objectes to bones.";
    addScreenshotFrame(120);
}
//----------------------------------------------------------------------------

void PlayPen_AttachObjectsToBones::setupContent()
{
    Entity *ent;
    for (int i = 0; i < 12; ++i)
    {
        ent = mSceneMgr->createEntity("robot" + StringConverter::toString(i), "robot.mesh");
        if (i % 2)
        {
            Entity* ent2 = mSceneMgr->createEntity("plane" + StringConverter::toString(i), "razor.mesh");
            ent->attachObjectToBone("Joint8", ent2);
        }
        else
        {
            ParticleSystem* psys = mSceneMgr->createParticleSystem("psys" + StringConverter::toString(i), "Examples/PurpleFountain");
            psys->getEmitter(0)->setTimeToLive(0.2);
            ent->attachObjectToBone("Joint15", psys);
        }
        // Add entity to the scene node
        mSceneMgr->getRootSceneNode()->createChildSceneNode(
            Vector3(0,0,(i*200)-(12*200/2)))->attachObject(ent);

        ent->getParentNode()->yaw(Degree(i * 45));

        AnimationState* animState = ent->getAnimationState("Walk");
        animState->setEnabled(true);
        mAnimStateList.push_back(animState);
    }



    // Give it a little ambience with lights
    Light* l;
    l = mSceneMgr->createLight("BlueLight");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-200,-80,-100))->attachObject(l);
    l->setDiffuseColour(0.5, 0.5, 1.0);

    l = mSceneMgr->createLight("GreenLight");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,0,-100))->attachObject(l);
    l->setDiffuseColour(0.5, 1.0, 0.5);

    // Position the camera
    mCameraNode->setPosition(400,120,500);
    mCameraNode->lookAt(Vector3(-50, 50, 0), Node::TS_PARENT);

    mSceneMgr->setAmbientLight(ColourValue(1,1,1,1));
    //mSceneMgr->showBoundingBoxes(true);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_BasicPlane::PlayPen_BasicPlane()
{
    mInfo["Title"] = "PlayPen_BasicPlane";
    mInfo["Description"] = "Tests basic planes.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_BasicPlane::setupContent()
{
    // Create a point light
    OrientedLightPtr l = mSceneMgr->createLight("MainLight");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(-Vector3::UNIT_Y);
    Entity *ent;

    // Define a floor plane mesh
    Plane p(Vector3::UNIT_Y, -200);
    MeshManager::getSingleton().createPlane(
        "FloorPlane",
        TRANSIENT_RESOURCE_GROUP,
        p, 2000, 2000, 1, 1, true, 1, 5, 5, Vector3::UNIT_Z);

    // Create an entity (the floor)
    ent = mSceneMgr->createEntity("floor", "FloorPlane");
    ent->setMaterialName("Examples/RustySteel");
    // ent->setMaterialName("BaseWhiteNoLighting");
    // ent->setMaterialName("BaseWhite");

    mSceneMgr->getRootSceneNode()->attachObject(ent);

    Entity* sphereEnt = mSceneMgr->createEntity("ogre", "ogrehead.mesh");

    SceneNode* mRootNode = mSceneMgr->getRootSceneNode();
    SceneNode* node = mSceneMgr->createSceneNode();
    node->attachObject(sphereEnt);
    mRootNode->addChild(node);

    //mCameraNode->lookAt(Vector3(1, 1, 1), Node::TS_PARENT);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_BillboardAccurateFacing::PlayPen_BillboardAccurateFacing()
{
    mInfo["Title"] = "PlayPen_BillboardAccurateFacing";
    mInfo["Description"] = "Tests billboard facing.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_BillboardAccurateFacing::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
    OrientedLightPtr l = mSceneMgr->createLight("light1");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(Vector3(-1, -1, 0.5).normalisedCopy());

    Plane plane(Vector3::UNIT_Y, -100);
    MeshManager::getSingleton().createPlane(
        "Myplane",
        TRANSIENT_RESOURCE_GROUP, plane,
        1500, 1500, 10, 10, true, 1, 5, 5, Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    BillboardSet* bbs = mSceneMgr->createBillboardSet("1");
    bbs->setDefaultDimensions(50, 50);
    bbs->createBillboard(-100, 25, 0);
    bbs->setBillboardType(BBT_ORIENTED_COMMON);
    bbs->setCommonDirection(Vector3::UNIT_Y);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(bbs);

    bbs = mSceneMgr->createBillboardSet("2");
    bbs->setDefaultDimensions(50, 50);
    bbs->createBillboard(100, 25, 0);
    bbs->setUseAccurateFacing(true);
    bbs->setBillboardType(BBT_ORIENTED_COMMON);
    bbs->setCommonDirection(Vector3::UNIT_Y);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(bbs);

    mCameraNode->setPosition(200,120,300);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_BillboardChain::PlayPen_BillboardChain()
{
    mInfo["Title"] = "PlayPen_BillboardChain";
    mInfo["Description"] = "Tests billboard chains.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_BillboardChain::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
    Vector3 dir(-1, -1, 0.5);
    dir.normalise();
    OrientedLightPtr l = mSceneMgr->createLight("light1");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(dir);

    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 100;
    MeshManager::getSingleton().createPlane(
        "Myplane",
        TRANSIENT_RESOURCE_GROUP, plane,
        1500,1500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    BillboardChain* chain = static_cast<BillboardChain*>(
        mSceneMgr->createMovableObject("1", "BillboardChain"));
    chain->setUseTextureCoords(true);
    chain->setUseVertexColours(false);

    BillboardChain::Element elem;
    elem.width = 10;
    elem.texCoord = 0;
    elem.position = Vector3(0,20,0);
    chain->addChainElement(0, elem);
    elem.position = Vector3(20,0,0);
    elem.texCoord = 1.0;
    chain->addChainElement(0, elem);
    elem.position = Vector3(40,10,0);
    elem.texCoord = 2.0;
    chain->addChainElement(0, elem);
    elem.position = Vector3(60,20,0);
    elem.texCoord = 3.0;
    chain->addChainElement(0, elem);
    elem.position = Vector3(80,40,0);
    elem.texCoord = 4.0;
    chain->addChainElement(0, elem);
    elem.position = Vector3(100,70,0);
    elem.texCoord = 5.0;
    chain->addChainElement(0, elem);

    // BillboardChain does not calculate normals, so result will be inconsistent.
    //chain->setMaterialName("Examples/ShowNormals");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(chain);

    mSceneMgr->showBoundingBoxes(true);

    mCameraNode->setPosition(-20,60,200);
    mCameraNode->lookAt(Vector3(60, 40, 0), Node::TS_PARENT);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_BillboardOrigins::PlayPen_BillboardOrigins()
{
    mInfo["Title"] = "PlayPen_BillboardOrigins";
    mInfo["Description"] = "Tests setting billboard origins.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_BillboardOrigins::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
    
    // Billboards currently have no normals.
    // Vector3 dir(-1, -1, 0.5);
    // dir.normalise();
    // Light* l = mSceneMgr->createLight("light1");
    // l->setType(Light::LT_DIRECTIONAL);
    // l->setDirection(dir);

    BillboardSet* bbs = mSceneMgr->createBillboardSet("1");
    bbs->setDefaultDimensions(50,50);
    bbs->createBillboard(0, 0, 0);
    bbs->setBillboardOrigin(BBO_TOP_LEFT);
    bbs->setMaterialName("2 - Default");
    // bbs->setBillboardType(BBT_ORIENTED_COMMON);
    bbs->setCommonDirection(Vector3::UNIT_Y);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(bbs);

    bbs = mSceneMgr->createBillboardSet("2");
    bbs->setDefaultDimensions(50,50);
    bbs->createBillboard(0, -10, 0);
    bbs->setBillboardOrigin(BBO_CENTER);
    bbs->setMaterialName("Examples/RustySteel");
    // bbs->setBillboardType(BBT_ORIENTED_COMMON);
    bbs->setCommonDirection(Vector3::UNIT_Y);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(bbs);

    bbs = mSceneMgr->createBillboardSet("3");
    bbs->setDefaultDimensions(50,50);
    bbs->createBillboard(0, -20, 0);
    bbs->setBillboardOrigin(BBO_BOTTOM_RIGHT);
    bbs->setMaterialName("Examples/OgreLogo");
    // bbs->setBillboardType(BBT_ORIENTED_COMMON);
    bbs->setCommonDirection(Vector3::UNIT_Y);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(bbs);

    mCameraNode->setPosition(0,160,1);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_BlendDiffuseColour::PlayPen_BlendDiffuseColour()
{
    mInfo["Title"] = "PlayPen_BlendDiffuseColour";
    mInfo["Description"] = "Tests diffuse blending.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_BlendDiffuseColour::setupContent()
{
    MaterialPtr mat = MaterialManager::getSingleton().create(
        "testBlendDiffuseColour", TRANSIENT_RESOURCE_GROUP);
    Pass* pass = mat->getTechnique(0)->getPass(0);
    // no lighting, it will mess up vertex colours
    pass->setLightingEnabled(false);
    // Make sure we pull in vertex colour as diffuse
    pass->setVertexColourTracking(TVC_DIFFUSE);
    // Base layer
    TextureUnitState* t = pass->createTextureUnitState("BeachStones.jpg");
    // don't want to bring in vertex diffuse on base layer
    t->setColourOperation(LBO_REPLACE);
    // Second layer (lerp based on colour)
    t = pass->createTextureUnitState("terr_dirt-grass.jpg");
    t->setColourOperationEx(LBX_BLEND_DIFFUSE_COLOUR);
    // third layer (lerp based on alpha)
    ManualObject* man = mSceneMgr->createManualObject("quad");
    man->begin("testBlendDiffuseColour");
    man->position(-100, 100, 0);
    man->textureCoord(0,0);
    man->colour(0, 0, 0);
    man->position(-100, -100, 0);
    man->textureCoord(0,1);
    man->colour(0.5, 0.5, 0.5);
    man->position(100, -100, 0);
    man->textureCoord(1,1);
    man->colour(1, 1, 1);
    man->position(100, 100, 0);
    man->textureCoord(1,0);
    man->colour(0.5, 0.5, 0.5);
    man->quad(0, 1, 2, 3);
    man->end();

    mSceneMgr->getRootSceneNode()->attachObject(man);

    mCameraNode->setPosition(0,0,250);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_BlitSubTextures::PlayPen_BlitSubTextures()
{
    mInfo["Title"] = "PlayPen_BlitSubTextures";
    mInfo["Description"] = "Tests blitting textures onto on another.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_BlitSubTextures::setupContent()
{
    TexturePtr src = TextureManager::getSingleton().load("ogrelogo.png", ASSETS_RESOURCE_GROUP);

    TexturePtr tex = TextureManager::getSingleton().createManual(
        "testblitdst",
        TRANSIENT_RESOURCE_GROUP, TEX_TYPE_2D, 1024, 1024, 1, 0, src->getFormat());

    Box srcBox;
    // This box should select from halfway through the head, to the
    // 'OG' part of the logo.
    srcBox.left = 376;
    srcBox.top = 379;
    srcBox.right = 376 + 224;
    srcBox.bottom = 379 + 278;
    srcBox.back = 1;
    srcBox.front = 0;

    // I was getting uninitialized memory written to the texture
    // buffer, so clear it explicitly.
    memset(tex->getBuffer()->lock(
        0, tex->getBuffer()->getSizeInBytes(),
        HardwareBuffer::HBL_NORMAL), 0, tex->getBuffer()->getSizeInBytes());
    tex->getBuffer()->unlock();

    tex->getBuffer()->blit(src->getBuffer(), srcBox, srcBox);

    MaterialPtr mat = MaterialManager::getSingleton().create(
        "testblit",
        TRANSIENT_RESOURCE_GROUP);

    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    p->createTextureUnitState(tex->getName());
    Entity *e = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);

    mCameraNode->setPosition(0,0,300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

    mWindow->getViewport(0)->setBackgroundColour(ColourValue::Green);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_HardwareScaleBlit::PlayPen_HardwareScaleBlit()
{
    mInfo["Title"] = "PlayPen_HardwareScaleBlit";
    mInfo["Description"] = "Tests blitting texture with hardware scaling.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_HardwareScaleBlit::setupContent()
{
    Image img;
    img.load("ogrelogo.png", ASSETS_RESOURCE_GROUP);

    TexturePtr tex = TextureManager::getSingleton().createManual(
        "testblitdst",
        TRANSIENT_RESOURCE_GROUP, TEX_TYPE_2D, 64, 64, 1, 0, img.getFormat());

    Box dstBox(0, 0, 64, 64);
    tex->getBuffer()->blitFromMemory(img.getPixelBox(), dstBox);

    MaterialPtr mat = MaterialManager::getSingleton().create(
        "testblit",
        TRANSIENT_RESOURCE_GROUP);

    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    p->createTextureUnitState(tex->getName());
    Entity *e = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);

    mCameraNode->setPosition(0,0,300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

    mWindow->getViewport(0)->setBackgroundColour(ColourValue::Green);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_Bsp::PlayPen_Bsp()
{
    mInfo["Title"] = "PlayPen_Bsp";
    mInfo["Description"] = "Tests BSP plugin.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_Bsp::setupContent()
{
    // Load Quake3 locations from a file
    ConfigFile cf;

    cf.load(mContext->getFSLayer().getConfigFilePath("quakemap.cfg"));

    String quakePk3 = cf.getSetting("Archive");
    String quakeLevel = cf.getSetting("Map");

    //ResourceGroupManager::getSingleton().addResourceLocation(quakePk3, "Zip");

    ResourceGroupManager::getSingleton().addResourceLocation(
        quakePk3, "Zip",
        ResourceGroupManager::getSingleton().getWorldResourceGroupName(), true);

    // Load world geometry
    mSceneMgr->setWorldGeometry(quakeLevel);

    // modify camera for close work
    mCamera->setNearClipDistance(4);
    mCamera->setFarClipDistance(4000);

    // Also change position, and set Quake-type orientation
    // Get random player start point
    ViewPoint vp = mSceneMgr->getSuggestedViewpoint(true);
    mCameraNode->setPosition(vp.position);
    mCameraNode->pitch(Degree(90)); // Quake uses X/Y horizon, Z up
    mCameraNode->rotate(vp.orientation);
    // Don't yaw along variable axis, causes leaning
    mCameraNode->setFixedYawAxis(true, Vector3::UNIT_Z);

    mCameraNode->yaw(Ogre::Degree(-90.f));
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_BuildTangentOnAnimatedMesh::PlayPen_BuildTangentOnAnimatedMesh()
{
    mInfo["Title"] = "PlayPen_BuildTangentOnAnimatedMesh";
    mInfo["Description"] = "Tests building tangents for an animated mesh.";
    addScreenshotFrame(50);
}
//----------------------------------------------------------------------------

void PlayPen_BuildTangentOnAnimatedMesh::setupContent()
{
    SceneNode* mTestNode[2];
    Light* mLight = 0;
    //mSceneMgr->setShadowTextureSize(512);
    //mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE);
    //mSceneMgr->setShadowFarDistance(1500);
    //mSceneMgr->setShadowColour(ColourValue(0.35, 0.35, 0.35));
    //mSceneMgr->setShadowFarDistance(800);
    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.3, 0.3, 0.3));

    mLight = mSceneMgr->createLight("MainLight");

    /*/
    // Directional test
    mLight->setType(Light::LT_DIRECTIONAL);
    Vector3 vec(-1,-1,0);
    vec.normalise();
    mLight->setDirection(vec);
    /*/
    // Point test
    mLight->setType(Light::LT_POINT);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0, 200, 0))->attachObject(mLight);
    //*/
    MeshPtr pMesh = MeshManager::getSingleton().load("ninja.mesh", ASSETS_RESOURCE_GROUP/*,
                                                                               HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY,
                                                                               HardwareBuffer::HBU_STATIC_WRITE_ONLY,
                                                                               true, true*/); //so we can still read it
    // Build tangent vectors, all our meshes use only 1 texture coordset
    pMesh->buildTangentVectors();

    Entity* pEnt = mSceneMgr->createEntity("Ninja", "ninja.mesh");
    pEnt->getAnimationState("Walk")->setEnabled(true);
    mTestNode[1] = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    mTestNode[1]->attachObject( pEnt );
    mTestNode[1]->translate(-100,-100,0);


    Plane plane(Vector3::UNIT_Y, -100);
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            1500,1500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt;
    pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    mCameraNode->setPosition(0,0,400);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_ClearScene::PlayPen_ClearScene()
{
    mInfo["Title"] = "PlayPen_ClearScene";
    mInfo["Description"] = "Tests clearing a running scene.";
    addScreenshotFrame(25);
}
//----------------------------------------------------------------------------

bool PlayPen_ClearScene::isScreenshotFrame(int frame)
{
    if(frame == 20)
        mSceneMgr->clearScene();
    return VisualTest::isScreenshotFrame(frame);
}
//----------------------------------------------------------------------------

void PlayPen_ClearScene::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue::White);

    // Define a floor plane mesh
    Plane p(Vector3::UNIT_Y, -200);
    MeshManager::getSingleton().createPlane("FloorPlane",
                                            TRANSIENT_RESOURCE_GROUP,
                                            p,200000,200000,20,20,true,1,50,50,Vector3::UNIT_Z);

    Entity* planeEnt;
    planeEnt = mSceneMgr->createEntity( "plane", "FloorPlane" );
    planeEnt->setMaterialName("Examples/Rockwall");
    mSceneMgr->getRootSceneNode()->attachObject(planeEnt);

    mCameraNode->setPosition(0,500,100);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_CompositorTechniqueSwitch::PlayPen_CompositorTechniqueSwitch()
{
    mInfo["Title"] = "PlayPen_CompositorTechniqueSwitch";
    mInfo["Description"] = "Tests switching compositor techniques rapidly.";
    addScreenshotFrame(15);
}
//----------------------------------------------------------------------------

void PlayPen_CompositorTechniqueSwitch::cleanupContent()
{
    CompositorManager::getSingleton().removeCompositorChain(mViewport);
}
//----------------------------------------------------------------------------

bool PlayPen_CompositorTechniqueSwitch::frameStarted(const FrameEvent& evt)
{
    mTimeUntilNextToggle -= evt.timeSinceLastFrame;

    if(mTimeUntilNextToggle <= 0.f)
    {
        ++mCompositorIndex;
        mCompositorIndex = mCompositorIndex % mCompositorSchemeList.size();
        mCompositorToSwitch->setScheme(mCompositorSchemeList[mCompositorIndex]);
        mTimeUntilNextToggle = 0.1;
    }

    return true;
}
//----------------------------------------------------------------------------

void PlayPen_CompositorTechniqueSwitch::setupContent()
{
    mTimeUntilNextToggle = 0.1f;// swap compositors every 10 frames
    CompositorManager& cmgr = CompositorManager::getSingleton();
    CompositorPtr compositor = cmgr.create("testtechswitch", TRANSIENT_RESOURCE_GROUP);
    // technique 1 (Invert)
    CompositionTechnique* ctech1 = compositor->createTechnique();
    CompositionTechnique::TextureDefinition* tdef =    ctech1->createTextureDefinition("rt0");
    tdef->formatList.push_back(PF_A8B8G8R8);
    tdef->width = tdef->height = 0;
    tdef->pooled = true;

    CompositionTargetPass* tpass = ctech1->createTargetPass();
    tpass->setOutputName("rt0");
    tpass->setInputMode(CompositionTargetPass::IM_PREVIOUS);
    CompositionTargetPass* tout = ctech1->getOutputTargetPass();
    tout->setInputMode(CompositionTargetPass::IM_NONE);
    CompositionPass* pass = tout->createPass(CompositionPass::PT_RENDERQUAD);
    pass->setMaterialName("Ogre/Compositor/Invert");
    pass->setInput(0, "rt0");

    // technique 2 (Tiling)
    ctech1 = compositor->createTechnique();
    ctech1->setSchemeName("Tiling");
    tdef =    ctech1->createTextureDefinition("rt0");
    tdef->formatList.push_back(PF_A8B8G8R8);
    tdef->width = tdef->height = 0;
    tdef->pooled = true;

    tpass = ctech1->createTargetPass();
    tpass->setOutputName("rt0");
    tpass->setInputMode(CompositionTargetPass::IM_PREVIOUS);
    tout = ctech1->getOutputTargetPass();
    tout->setInputMode(CompositionTargetPass::IM_NONE);
    pass = tout->createPass(CompositionPass::PT_RENDERQUAD);
    pass->setMaterialName("Ogre/Compositor/Tiling");
    pass->setInput(0, "rt0");

    compositor->load();

    Entity* e = mSceneMgr->createEntity("1", "knot.mesh");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);
    mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox", 1000);

    // enable compositor (should pick first technique)
    Viewport* vp = mWindow->getViewport(0);

    mCompositorToSwitch = cmgr.addCompositor(vp, compositor->getName());
    mCompositorSchemeList.push_back("");
    mCompositorSchemeList.push_back("Tiling");

    cmgr.setCompositorEnabled(vp, compositor->getName(), true);

    mCameraNode->setPosition(0, 0, -300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

    mCompositorIndex = 0;

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_CompositorTextureShadows::PlayPen_CompositorTextureShadows()
{
    mInfo["Title"] = "PlayPen_CompositorTextureShadows";
    mInfo["Description"] = "Tests applying a compositor to a texture shadow manager.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_CompositorTextureShadows::cleanupContent()
{
    TexturePtr shadowTex = mSceneMgr->getShadowTexture(0);
    RenderTarget* shadowRtt = shadowTex->getBuffer()->getRenderTarget();
    Viewport* vp = shadowRtt->getViewport(0);
    CompositorManager::getSingleton().removeCompositorChain(vp);
    clearDebugTextureOverlays();
}
//----------------------------------------------------------------------------

void PlayPen_CompositorTextureShadows::setupContent()
{
    SceneNode* mTestNode[10];

    mSceneMgr->setShadowTextureSize(512);
    mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE);
    mSceneMgr->setShadowFarDistance(1500);
    mSceneMgr->setShadowColour(ColourValue(0.35, 0.35, 0.35));
    //mSceneMgr->setShadowFarDistance(800);
    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.3, 0.3, 0.3));

    Light* mLight = mSceneMgr->createLight("MainLight");

    /*
    // Directional test
    mLight->setType(Light::LT_DIRECTIONAL);
    Vector3 vec(-1,-1,0);
    vec.normalise();
    mLight->setDirection(vec);

    */
    // Spotlight test
    mLight->setType(Light::LT_SPOTLIGHT);
    mLight->setDiffuseColour(1.0, 1.0, 0.8);
    mTestNode[0] = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    mTestNode[0]->setPosition(800,600,0);
    mTestNode[0]->lookAt(Vector3(0,0,0), Node::TS_WORLD);
    mTestNode[0]->attachObject(mLight);


    mTestNode[1] = mSceneMgr->getRootSceneNode()->createChildSceneNode();


    Entity* pEnt;
    pEnt = mSceneMgr->createEntity( "1", "robot.mesh" );
    //pEnt->setRenderingDistance(100);
    AnimationState* mAnimState = pEnt->getAnimationState("Walk");
    mAnimState->setEnabled(true);
    mAnimStateList.push_back(mAnimState);
    //pEnt->setMaterialName("2 - Default");
    mTestNode[1]->attachObject( pEnt );
    mTestNode[1]->translate(0,-100,0);

    pEnt = mSceneMgr->createEntity( "3", "knot.mesh" );
    mTestNode[2] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-200, 0, -200));
    mTestNode[2]->attachObject( pEnt );

    // Transparent object (can force cast shadows)
    pEnt = mSceneMgr->createEntity( "3.5", "knot.mesh" );
    MaterialPtr tmat = MaterialManager::getSingleton().create("TestAlphaTransparency",
                                                              TRANSIENT_RESOURCE_GROUP);
    tmat->setTransparencyCastsShadows(true);
    Pass* tpass = tmat->getTechnique(0)->getPass(0);
    tpass->setAlphaRejectSettings(CMPF_GREATER, 150);
    tpass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
    tpass->createTextureUnitState("gras_02.png");
    tpass->setCullingMode(CULL_NONE);

    pEnt->setMaterialName("TestAlphaTransparency");
    mTestNode[3] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(350, 0, -200));
    mTestNode[3]->attachObject( pEnt );

    pEnt = mSceneMgr->createEntity( "4", "knot.mesh" );
    mTestNode[2] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(100, 0, 200));
    mTestNode[2]->attachObject( pEnt );

    mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");


    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 100;
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            1500,1500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt;
    pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    // Set up a debug panel to display the shadow
    addTextureShadowDebugOverlay(1, mSceneMgr);



    ParticleSystem* pSys2 = mSceneMgr->createParticleSystem("smoke",
                                                            "Examples/Smoke");
    mTestNode[4] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-300, -100, 200));
    mTestNode[4]->attachObject(pSys2);

    TexturePtr shadowTex = mSceneMgr->getShadowTexture(0);
    RenderTarget* shadowRtt = shadowTex->getBuffer()->getRenderTarget();
    Viewport* vp = shadowRtt->getViewport(0);
    // This originally used gaussian blur, but since compositor logic stuff has changed since the test
    // was originally written and I'm not especially familiar with it, I just swapped to a random
    // compositor (it still tests the required functionality)
    CompositorManager::getSingleton().addCompositor(vp, "Laplace");
    CompositorManager::getSingleton().setCompositorEnabled(
        vp, "Laplace", true);

    mCameraNode->setPosition(400, 250, 350);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_CubeDDS::PlayPen_CubeDDS()
{
    mInfo["Title"] = "PlayPen_CubeDDS";
    mInfo["Description"] = "Tests DDS cubemaps.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_CubeDDS::setupContent()
{
    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Tests");

    MaterialPtr mat = MaterialManager::getSingleton().create("testcube",
                                                             TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    TextureUnitState* t = p->createTextureUnitState();
    t->setTextureName("grace_cube.dds", TEX_TYPE_CUBE_MAP);
    t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
    t->setEnvironmentMap(true, TextureUnitState::ENV_REFLECTION);
    Entity* e = mSceneMgr->createEntity("1", "sphere.mesh");
    e->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);

    mCameraNode->setPosition(300,0,0);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_CustomProjectionMatrix::PlayPen_CustomProjectionMatrix()
{
    mInfo["Title"] = "PlayPen_CustomProjectionMatrix";
    mInfo["Description"] = "Tests custom projection matrix.";
}
//----------------------------------------------------------------------------

void PlayPen_CustomProjectionMatrix::setupContent()
{
    PlayPen_LotsAndLotsOfEntities::setupContent();
    Matrix4 mat = mCamera->getProjectionMatrix();
    mCamera->setCustomProjectionMatrix(true, mat);
    mat = mCamera->getProjectionMatrix();

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_DepthBias::PlayPen_DepthBias()
{
    mInfo["Title"] = "PlayPen_DepthBias";
    mInfo["Description"] = "Tests depth biasing.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_DepthBias::setupContent()
{
    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Tests");

    mSceneMgr->setAmbientLight(ColourValue::White);

    MaterialPtr mat = MaterialManager::getSingleton().create("mat1",
                                                             TRANSIENT_RESOURCE_GROUP);
    // mat->setSceneBlending(SBT_TRANSPARENT_ALPHA);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    p->createTextureUnitState("BumpyMetal.jpg");
    // t->setColourOperation(LBO_ALPHA_BLEND);

    const String meshName("cube.mesh");
    Entity* entity = mSceneMgr->createEntity("base", meshName);
    entity->setMaterialName("mat1");
    mSceneMgr->getRootSceneNode()->attachObject(entity);

    entity = mSceneMgr->createEntity("base2", meshName);
    entity->setMaterialName("Examples/SphereMappedRustySteel");
    SceneNode* n = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    n->setPosition(-30, 0, 0);
    n->yaw(Degree(45));
    n->attachObject(entity);

    // for (size_t i = 0; i <= 6; ++i)
    for (size_t i = 0; i <= 3; ++i)
    {
        String name("decal");
        name += StringConverter::toString(i);

        MaterialPtr pMat = MaterialManager::getSingleton().create(name, TRANSIENT_RESOURCE_GROUP);

        p = pMat->getTechnique(0)->getPass(0);
        p->setLightingEnabled(false);
        p->setAlphaRejectSettings(CMPF_GREATER_EQUAL, 128);
        p->setSceneBlending(SBT_TRANSPARENT_ALPHA);
        p->setDepthBias(i);
        p->createTextureUnitState(name + ".png");
        // t->setColourOperation(LBO_ALPHA_BLEND);

        entity = mSceneMgr->createEntity(name, meshName);
        entity->setMaterialName(name);
        mSceneMgr->getRootSceneNode()->attachObject(entity);
    }

    mCameraNode->setPosition(0,0,200);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_DepthShadowMap::PlayPen_DepthShadowMap()
{
    mInfo["Title"] = "PlayPen_DepthShadowMap";
    mInfo["Description"] = "Tests depth shadowmapping.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_DepthShadowMap::setupContent()
{
    mSceneMgr->setShadowTextureCount(1);
    mSceneMgr->setShadowTextureConfig(0, 1024, 1024, PF_FLOAT32_R);
    mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_ADDITIVE_INTEGRATED);
    mSceneMgr->setShadowCasterRenderBackFaces(false);
    mSceneMgr->setShadowFarDistance(500);

#ifdef OGRE_BUILD_COMPONENT_RTSHADERSYSTEM
    // Make this viewport work with shader generator scheme.
    mViewport->setMaterialScheme(MSN_SHADERGEN);
    RTShader::ShaderGenerator& rtShaderGen = RTShader::ShaderGenerator::getSingleton();
    RTShader::RenderState* schemRenderState = rtShaderGen.getRenderState(MSN_SHADERGEN);
    auto subRenderState = rtShaderGen.createSubRenderState(RTShader::SRS_SHADOW_MAPPING);
    schemRenderState->addTemplateSubRenderState(subRenderState);
#endif
    mSceneMgr->setShadowTextureCasterMaterial(
        MaterialManager::getSingleton().getByName("PSSM/shadow_caster", "General"));

    // ground plane
    movablePlane.reset(new MovablePlane(Vector3::UNIT_Y, 0.f));

    mSceneMgr->setShadowCameraSetup(PlaneOptimalShadowCameraSetup::create(movablePlane.get()));

    // Single light
    Light* l = mSceneMgr->createLight("l1");
    l->setType(Light::LT_POINT);
    Vector3 pos(-150, 100, -50);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(pos)->attachObject(l);

    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, *movablePlane,
                                            500,500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt;
    pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("Examples/Rockwall");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    // box
    ManualObject* man = mSceneMgr->createManualObject("box");
    Real boxsize = 50;
    Real boxsizehalf = boxsize / 2.0;
    man->begin("BaseWhite");
    man->position(-boxsizehalf, 0, boxsizehalf);
    man->normal(0, 0, 0);
    man->position(boxsizehalf, 0, boxsizehalf);
    man->normal(0, 0, 0);
    man->position(boxsizehalf, 0, -boxsizehalf);
    man->normal(0, 0, 0);
    man->position(-boxsizehalf, 0, -boxsizehalf);
    man->normal(0, 0, 0);
    man->position(-boxsizehalf, boxsize, boxsizehalf);
    man->normal(0, 0, 0);
    man->position(boxsizehalf, boxsize, boxsizehalf);
    man->normal(0, 0, 0);
    man->position(boxsizehalf, boxsize, -boxsizehalf);
    man->normal(0, 0, 0);
    man->position(-boxsizehalf, boxsize, -boxsizehalf);
    man->normal(0, 0, 0);
    man->quad(3, 2, 1, 0);
    man->quad(4, 5, 6, 7);
    man->quad(0, 1, 5, 4);
    man->quad(1, 2, 6, 5);
    man->quad(2, 3, 7, 6);
    man->quad(3, 0, 4, 7);
    man->end();

    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(man);

    mCameraNode->setPosition(150, 100, 150);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

    // Create RTT
    //TexturePtr rtt = TextureManager::getSingleton().createManual("rtt1", TRANSIENT_RESOURCE_GROUP,
    //    TEX_TYPE_2D, 1024, 1024, 1, 0, PF_FLOAT32_R);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

Entity* pTexListenerPlaneEnt = 0;// yucky global...
Camera* theCam = 0;

class RefractionTextureListener : public RenderTargetListener
{
public:
    void preRenderTargetUpdate(const RenderTargetEvent& evt) override
    {
        pTexListenerPlaneEnt->setVisible(false);

    }
    void postRenderTargetUpdate(const RenderTargetEvent& evt) override
    {
        pTexListenerPlaneEnt->setVisible(true);
    }

};

class ReflectionTextureListener : public RenderTargetListener
{
public:
    void preRenderTargetUpdate(const RenderTargetEvent& evt) override
    {
        static Plane reflectPlane(Vector3::UNIT_Y, -100);
        pTexListenerPlaneEnt->setVisible(false);
        theCam->enableReflection(reflectPlane);

    }
    void postRenderTargetUpdate(const RenderTargetEvent& evt) override
    {
        pTexListenerPlaneEnt->setVisible(true);
        theCam->disableReflection();
    }

};

PlayPen_Distortion::PlayPen_Distortion()
{
    mInfo["Title"] = "PlayPen_Distortion";
    mInfo["Description"] = "Tests distortion.";
    addScreenshotFrame(15);

    mRefractionListener = new RefractionTextureListener();
    mReflectionListener = new ReflectionTextureListener();
}
//----------------------------------------------------------------------------

PlayPen_Distortion::~PlayPen_Distortion()
{
    delete mRefractionListener;
    delete mReflectionListener;
}
//----------------------------------------------------------------------------

void PlayPen_Distortion::cleanupContent()
{
    TexturePtr rttTex = TextureManager::getSingleton().getByName("Refraction", TRANSIENT_RESOURCE_GROUP);
    rttTex->getBuffer()->getRenderTarget()->removeAllListeners();
    rttTex->unload();
    rttTex = TextureManager::getSingleton().getByName("Reflection", TRANSIENT_RESOURCE_GROUP);
    rttTex->getBuffer()->getRenderTarget()->removeAllListeners();
    rttTex->unload();
}
//----------------------------------------------------------------------------

void PlayPen_Distortion::setupContent()
{
    theCam = mCamera;
    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

    // Create a point light
    OrientedLightPtr l = mSceneMgr->createLight("MainLight");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(-Vector3::UNIT_Y);

    Entity* pEnt;

    TexturePtr rttTex = TextureManager::getSingleton().createManual("Refraction",
                                                                    TRANSIENT_RESOURCE_GROUP, TEX_TYPE_2D,
                                                                    512, 512, 1, 0, PF_R8G8B8, TU_RENDERTARGET);
    {
        Viewport *v = rttTex->getBuffer()->getRenderTarget()->addViewport( mCamera );
        MaterialPtr mat = MaterialManager::getSingleton().getByName("Examples/FresnelReflectionRefraction");
        mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setProjectiveTexturing(true, mCamera);
        mat->getTechnique(0)->getPass(0)->getTextureUnitState(2)->setTextureName("Refraction");
        v->setOverlaysEnabled(false);
        rttTex->getBuffer()->getRenderTarget()->addListener(mRefractionListener);
    }

    rttTex = TextureManager::getSingleton().createManual("Reflection",
                                                         TRANSIENT_RESOURCE_GROUP, TEX_TYPE_2D,
                                                         512, 512, 1, 0, PF_R8G8B8, TU_RENDERTARGET);
    {
        Viewport *v = rttTex->getBuffer()->getRenderTarget()->addViewport( mCamera );
        MaterialPtr mat = MaterialManager::getSingleton().getByName("Examples/FresnelReflectionRefraction");
        mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName("Reflection");
        v->setOverlaysEnabled(false);
        rttTex->getBuffer()->getRenderTarget()->addListener(mReflectionListener);
    }
    // Define a floor plane mesh
    Plane p(Vector3::UNIT_Y, -100);
    MeshManager::getSingleton().createPlane("WallPlane",
                                            TRANSIENT_RESOURCE_GROUP,
                                            p,1500,1500,10,10,true,1,5,5,Vector3::UNIT_Z);
    pTexListenerPlaneEnt = mSceneMgr->createEntity( "5", "WallPlane" );
    pTexListenerPlaneEnt->setMaterialName("Examples/FresnelReflectionRefraction");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pTexListenerPlaneEnt);

    mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");

    for (int i = 0; i < 10; ++i)
    {
        pEnt = mSceneMgr->createEntity( "ogre" + StringConverter::toString(i), "ogrehead.mesh" );
        mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(i*100 - 500, -75, 0))->attachObject(pEnt);
        pEnt = mSceneMgr->createEntity( "knot" + StringConverter::toString(i), "knot.mesh" );
        mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(i*100 - 500, 140, 0))->attachObject(pEnt);
    }

    mCameraNode->setPosition(100,200,300);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_Dxt1Alpha::PlayPen_Dxt1Alpha()
{
    mInfo["Title"] = "PlayPen_Dxt1Alpha";
    mInfo["Description"] = "Tests dxt1 loading with alpha.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_Dxt1Alpha::setupContent()
{
    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Tests");

    MaterialPtr mat = MaterialManager::getSingleton().create("testdxt",
                                                             TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setSceneBlending(SBT_TRANSPARENT_ALPHA);
    p->setAlphaRejectSettings(CMPF_GREATER, 128);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    p->createTextureUnitState("gras_02_dxt1.dds");
    Entity *e = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);

    mCameraNode->setPosition(0,0,300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

}
//----------------------------------------------------------------------------
PlayPen_AlphaTex::PlayPen_AlphaTex()
{
    mInfo["Title"] = "PlayPen_AlphaTex";
    mInfo["Description"] = "Tests alpha only texture.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_AlphaTex::setupContent()
{
    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Tests");

    TexturePtr tex =
        TextureManager::getSingleton().load("terrain.png", TRANSIENT_RESOURCE_GROUP, TEX_TYPE_2D, 0, 1.0f, PF_A8);

    MaterialPtr mat = MaterialManager::getSingleton().create("test", TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    p->setSceneBlending(SBT_TRANSPARENT_ALPHA);
    p->createTextureUnitState()->setTexture(tex);
    Entity *e = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);

    mCameraNode->setPosition(0,0,-300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);
    mWindow->getViewport(0)->setBackgroundColour(ColourValue::Green);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
PlayPen_TwoSidedLighting::PlayPen_TwoSidedLighting()
{
    mInfo["Title"] = "PlayPen_TwoSidedLighting";
    mInfo["Description"] = "Tests alpha only texture.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_TwoSidedLighting::setupContent()
{
    // Make this viewport work with shader generator scheme.
    mViewport->setMaterialScheme(MSN_SHADERGEN);

    Entity *e = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
    e->setMaterialName("Tests/TwoSidedLighting");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);
    mViewport->setBackgroundColour(ColourValue(0.2, 0.2, 0.2));

    mCameraNode->setPosition(0,0,-300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

    auto l = mSceneMgr->createLight();
    l->setSpecularColour(ColourValue::White);
    mCameraNode->attachObject(l);
}
//----------------------------------------------------------------------------
PlayPen_Dxt1::PlayPen_Dxt1()
{
    mInfo["Title"] = "PlayPen_Dxt1";
    mInfo["Description"] = "Tests dxt1 loading.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_Dxt1::setupContent()
{
    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Tests");

    MaterialPtr mat = MaterialManager::getSingleton().create("testdxt",
                                                             TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    p->createTextureUnitState("BumpyMetal_dxt1.dds");
    Entity *e = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);

    mCameraNode->setPosition(0,0,-300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_Dxt1FromMemory::PlayPen_Dxt1FromMemory()
{
    mInfo["Title"] = "PlayPen_Dxt1FromMemory";
    mInfo["Description"] = "Tests dxt1 loading from memory.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_Dxt1FromMemory::setupContent()
{
    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Tests");

    DataStreamPtr stream = ResourceGroupManager::getSingleton().openResource("BumpyMetal_dxt1.dds", "Tests");
    // manually load into image
    Image img;
    img.load(stream, "dds");
    TextureManager::getSingleton().loadImage("testdxtfrommem", TRANSIENT_RESOURCE_GROUP, img);



    MaterialPtr mat = MaterialManager::getSingleton().create("testdxt",
                                                             TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    p->createTextureUnitState("testdxtfrommem");
    Entity *e = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);

    mCameraNode->setPosition(0,0,-300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_Dxt3::PlayPen_Dxt3()
{
    mInfo["Title"] = "PlayPen_Dxt3";
    mInfo["Description"] = "Tests dxt3 loading.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_Dxt3::setupContent()
{
    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Tests");

    MaterialPtr mat = MaterialManager::getSingleton().create("testdxt",
                                                             TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    p->setSceneBlending(SBT_TRANSPARENT_ALPHA);
    p->createTextureUnitState("ogreborderUp_dxt3.dds");
    Entity *e = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);
    mWindow->getViewport(0)->setBackgroundColour(ColourValue::Red);

    mCameraNode->setPosition(0,0,300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_Dxt3FromMemory::PlayPen_Dxt3FromMemory()
{
    mInfo["Title"] = "PlayPen_Dxt3FromMemory";
    mInfo["Description"] = "Tests dxt3 loading from memory.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_Dxt3FromMemory::setupContent()
{
    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Tests");

    DataStreamPtr stream = ResourceGroupManager::getSingleton().openResource("ogreborderUp_dxt3.dds", "Tests");
    // manually load into image
    Image img;
    img.load(stream, "dds");
    TextureManager::getSingleton().loadImage("testdxtfrommem", TRANSIENT_RESOURCE_GROUP, img);

    MaterialPtr mat = MaterialManager::getSingleton().create("testdxt",
                                                             TRANSIENT_RESOURCE_GROUP);

    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    p->setSceneBlending(SBT_TRANSPARENT_ALPHA);
    p->setAlphaRejectSettings(CMPF_GREATER, 128);
    mat->setReceiveShadows(false);
    TextureUnitState* t = p->createTextureUnitState("testdxtfrommem");
    t->setTextureScale(0.5,0.5);
    Entity *e = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    SceneNode* n = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    n->setPosition(-50, 0, 35);
    n->yaw(Degree(90));
    n->attachObject(e);
    mWindow->getViewport(0)->setBackgroundColour(ColourValue::Red);

    mCameraNode->setPosition(0,0,300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_Dxt5::PlayPen_Dxt5()
{
    mInfo["Title"] = "PlayPen_Dxt5";
    mInfo["Description"] = "Tests dxt5 loading.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_Dxt5::setupContent()
{
    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Tests");

    MaterialPtr mat = MaterialManager::getSingleton().create("testdxt",
                                                             TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    p->setSceneBlending(SBT_TRANSPARENT_ALPHA);
    p->createTextureUnitState("ogreborderUp_dxt5.dds");
    Entity *e = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);
    mWindow->getViewport(0)->setBackgroundColour(ColourValue::Red);

    mCameraNode->setPosition(0,0,300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_FarFromOrigin::PlayPen_FarFromOrigin()
{
    mInfo["Title"] = "PlayPen_FarFromOrigin";
    mInfo["Description"] = "Tests rending far from the origin.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_FarFromOrigin::cleanupContent()
{
    //clearDebugTextureOverlays();
}

void PlayPen_FarFromOrigin::setupContent()
{
    SceneNode* mTestNode[5];
    mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE);
    mSceneMgr->setShadowTextureSettings(1024, 2);

    Vector3 offset(100000, 0, 100000);
    //Vector3 offset(0, 0, 0);

    mSceneMgr->setAmbientLight(ColourValue(0.1, 0.1, 0.1));

    // Directional test
    {
        OrientedLightPtr mLight = mSceneMgr->createLight("MainLight");
        mLight->setType(Light::LT_DIRECTIONAL);
        Vector3 vec(-1, -1, 0);
        vec.normalise();
        mLight->setDirection(vec);
        mLight->setDiffuseColour(0.5, 0.5, 1.0);
    }

    // Spotlight test
    auto mLight = mSceneMgr->createLight("SpotLight");
    mLight->setType(Light::LT_SPOTLIGHT);
    mLight->setAttenuation(10000, 1, 0, 0);
    mLight->setDiffuseColour(1.0, 1.0, 0.5);

    mTestNode[0] = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    mTestNode[0]->setPosition(offset + Vector3(-400,300,1000));
    mTestNode[0]->lookAt(offset, Node::TS_WORLD);
    mTestNode[0]->attachObject(mLight);


    mTestNode[1] = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    mTestNode[1]->setPosition(offset);

    Entity* pEnt;
    pEnt = mSceneMgr->createEntity( "1", "knot.mesh" );
    mTestNode[1]->attachObject( pEnt );


    mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");


    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 100;
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            2500,2500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt;
    pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(offset)->attachObject(pPlaneEnt);

    ParticleSystem* pSys2 = mSceneMgr->createParticleSystem("smoke",
                                                            "Examples/Smoke");
    mTestNode[4] = mSceneMgr->getRootSceneNode()->createChildSceneNode(offset + Vector3(-300, -100, 200));
    mTestNode[4]->attachObject(pSys2);

    mCameraNode->setPosition(offset + Vector3(0, 1000, 500));
    mCameraNode->lookAt(offset, Node::TS_PARENT);
    mCamera->setFarClipDistance(10000);

    mSceneMgr->setCameraRelativeRendering(true);

    mSceneMgr->setShadowCameraSetup(FocusedShadowCameraSetup::create());
    //addTextureShadowDebugOverlay(1, mSceneMgr);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_Float128DDS::PlayPen_Float128DDS()
{
    mInfo["Title"] = "PlayPen_Float128DDS";
    mInfo["Description"] = "Tests 128bit floating point dds textures.";
    addScreenshotFrame(250);
}
//----------------------------------------------------------------------------

void PlayPen_Float128DDS::setupContent()
{
    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Tests");

    MaterialPtr mat = MaterialManager::getSingleton().create("testdds",
                                                             TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    p->setSceneBlending(SBT_TRANSPARENT_ALPHA);
    p->createTextureUnitState("ogreborderUp_float128.dds");
    Entity *e = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);
    mWindow->getViewport(0)->setBackgroundColour(ColourValue::Red);

    mCameraNode->setPosition(0,0,300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_Float16DDS::PlayPen_Float16DDS()
{
    mInfo["Title"] = "PlayPen_Float16DDS";
    mInfo["Description"] = "Tests 16bit floating point dds textures.";
    addScreenshotFrame(250);
}
//----------------------------------------------------------------------------

void PlayPen_Float16DDS::setupContent()
{
    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Tests");

    MaterialPtr mat = MaterialManager::getSingleton().create("testdds",
                                                             TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    p->createTextureUnitState("BumpyMetal_float16.dds");
    Entity *e = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);
    mWindow->getViewport(0)->setBackgroundColour(ColourValue::Red);

    mCameraNode->setPosition(0,0,300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_Float32DDS::PlayPen_Float32DDS()
{
    mInfo["Title"] = "PlayPen_Float32DDS";
    mInfo["Description"] = "Tests 32bit floating point dds textures.";
    addScreenshotFrame(250);
}
//----------------------------------------------------------------------------

void PlayPen_Float32DDS::setupContent()
{
    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Tests");

    MaterialPtr mat = MaterialManager::getSingleton().create("testdds",
                                                             TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    p->createTextureUnitState("BumpyMetal_float32.dds");
    Entity *e = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);
    mWindow->getViewport(0)->setBackgroundColour(ColourValue::Red);

    mCameraNode->setPosition(0,0,300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_Float64DDS::PlayPen_Float64DDS()
{
    mInfo["Title"] = "PlayPen_Float64DDS";
    mInfo["Description"] = "Tests 64bit floating point dds textures.";
    addScreenshotFrame(250);
}
//----------------------------------------------------------------------------

void PlayPen_Float64DDS::setupContent()
{
    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Tests");

    MaterialPtr mat = MaterialManager::getSingleton().create("testdds",
                                                             TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    p->setSceneBlending(SBT_TRANSPARENT_ALPHA);
    p->createTextureUnitState("ogreborderUp_float64.dds");
    Entity *e = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);
    mWindow->getViewport(0)->setBackgroundColour(ColourValue::Red);

    mCameraNode->setPosition(0,0,300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_GeometryShaders::PlayPen_GeometryShaders()
{
    mInfo["Title"] = "PlayPen_GeometryShaders";
    mInfo["Description"] = "Tests geometry shaders.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_GeometryShaders::testCapabilities(const Ogre::RenderSystemCapabilities* caps)
{
    if(!caps->hasCapability(RSC_GEOMETRY_PROGRAM))
        throw Ogre::Exception(999, "Video card doesn't support geometry shaders.", "testCapabilities");
}
//----------------------------------------------------------------------------

void PlayPen_GeometryShaders::setupContent()
{
    // Check capabilities
    const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities();
    if (!caps->hasCapability(RSC_GEOMETRY_PROGRAM))
    {
        OGRE_EXCEPT(Ogre::Exception::ERR_NOT_IMPLEMENTED, 
                    "Your card does not support geometry programs, so cannot "
                    "run this demo. Sorry!",
                    "GeometryShading::createScene");
    }

    int maxOutputVertices = caps->getGeometryProgramNumOutputVertices();
    Ogre::LogManager::getSingleton().getDefaultLog()->stream() <<
        "Num output vertices per geometry shader run : " << maxOutputVertices;

    Entity *ent = mSceneMgr->createEntity("head", "ogrehead.mesh");
    
    // Set all of the material's sub entities to use the new material
    for (unsigned int i = 0; i < ent->getNumSubEntities(); i++)
    {
        ent->getSubEntity(i)->setMaterialName("Ogre/GPTest/Swizzle");
    }

    // Add entity to the root scene node
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);

    mWindow->getViewport(0)->setBackgroundColour(ColourValue::Green);

    mCameraNode->setPosition(20, 0, 100);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_InfiniteAAB::PlayPen_InfiniteAAB()
{
    mInfo["Title"] = "PlayPen_InfiniteAAB";
    mInfo["Description"] = "Tests finite/infinite AABBs.";
    addScreenshotFrame(15);
}
//----------------------------------------------------------------------------

void PlayPen_InfiniteAAB::setupContent()
{
    ResourceGroupManager::getSingleton().setWorldResourceGroupName("BSPWorld");
    mSceneMgr->setWorldGeometry("ogretestmap.bsp");

    AxisAlignedBox b1; // null
    assert( b1.isNull() );

    AxisAlignedBox b2(Vector3::ZERO, 5.0 * Vector3::UNIT_SCALE); // finite
    assert( b2.isFinite() );

    AxisAlignedBox b3;
    b3.setInfinite();
    assert( b3.isInfinite() );

    {
        // Create background material
        MaterialPtr material = MaterialManager::getSingleton().create("Background", "General");
        material->getTechnique(0)->getPass(0)->createTextureUnitState("rockwall.tga");
        material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false);
        material->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false);
        material->getTechnique(0)->getPass(0)->setLightingEnabled(false);

        // Create left background rectangle
        // NOTE: Uses finite aab
        Rectangle2D* rect1 = new Rectangle2D(true);
        rect1->setCorners(-0.5, 0.1, -0.1, -0.1);
        // Hacky, set small bounding box, to show problem
        rect1->setBoundingBox(AxisAlignedBox(-10.0*Vector3::UNIT_SCALE, 10.0*Vector3::UNIT_SCALE));
        rect1->setMaterial(material);
        rect1->setRenderQueueGroup(RENDER_QUEUE_OVERLAY - 1);
        SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode("Background1");
        node->attachObject(rect1);

        // Create right background rectangle
        // NOTE: Uses infinite aab
        Rectangle2D* rect2 = new Rectangle2D(true);
        rect2->setCorners(0.1, 0.1, 0.5, -0.1);
        AxisAlignedBox aabInf; aabInf.setInfinite();
        rect2->setBoundingBox(aabInf);
        rect2->setMaterial(material);
        rect2->setRenderQueueGroup(RENDER_QUEUE_OVERLAY - 1);
        node = mSceneMgr->getRootSceneNode()->createChildSceneNode("Background2");
        node->attachObject(rect2);

        // Create a manual object for 2D
        ManualObject* manual = mSceneMgr->createManualObject("manual");
        manual->setUseIdentityProjection(true);
        manual->setUseIdentityView(true);
        manual->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_STRIP);
        manual->position(-0.2, -0.2, 0.0);
        manual->position( 0.2, -0.2, 0.0);
        manual->position( 0.2,  0.2, 0.0);
        manual->position(-0.2,  0.2, 0.0);
        manual->index(0);
        manual->index(1);
        manual->index(2);
        manual->index(3);
        manual->index(0);
        manual->end();
        manual->setBoundingBox(aabInf); // Use infinite aab to always stay visible
        rect2->setRenderQueueGroup(RENDER_QUEUE_OVERLAY - 1);
        mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual);
    }

    mSceneMgr->showBoundingBoxes(true);

    Entity* ent = mSceneMgr->createEntity("test", "ogrehead.mesh");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(
        "test", 50.0 * Vector3::UNIT_X)->attachObject(ent);

    mCameraNode->setPosition(100,50,350);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);
}
void PlayPen_InfiniteAAB::cleanupContent()
{
    Ogre::ResourceGroupManager::getSingleton().clearResourceGroup("BSPWorld");
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_LightClipPlanes::PlayPen_LightClipPlanes()
{
    mInfo["Title"] = "PlayPen_LightClipPlanes";
    mInfo["Description"] = "Tests light clipping planes.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_LightClipPlanes::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue::White);


    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 0;
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            4500,4500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );

    MaterialPtr mat = MaterialManager::getSingleton()
                          .getByName("Examples/GrassFloor")
                          ->clone("Myplane/Material", TRANSIENT_RESOURCE_GROUP);

    pPlaneEnt->setMaterial(mat);
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(150,0,100))->attachObject(pPlaneEnt);

    Real lightRange = 1000;
    Real spotWidth = 300;

    ManualObject* debugSphere = mSceneMgr->createManualObject("debugSphere");
    debugSphere->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_STRIP);
    for (int i = 0; i <= 20; ++i)
    {
        Vector3 basePos(spotWidth, 0, 0);
        Quaternion quat;
        quat.FromAngleAxis(Radian(((float)i/(float)20)*Math::TWO_PI), Vector3::UNIT_Y);
        basePos = quat * basePos;
        debugSphere->position(basePos);
    }
    debugSphere->end();

    Light* l = mSceneMgr->createLight("l1");
    l->setAttenuation(lightRange, 1, 0, 0);
    SceneNode* n = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(100,0,0));
    n->attachObject(debugSphere);
    /* SPOT LIGHT
     */
    // match spot width to groud
    Real spotHeight = lightRange * 0.5;
    n = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(100,spotHeight,0));
    l->setType(Light::LT_SPOTLIGHT);
    Radian spotAngle = Math::ATan(spotWidth / spotHeight) * 2;
    l->setSpotlightOuterAngle(spotAngle);
    l->setSpotlightInnerAngle(spotAngle * 0.75);
    Vector3 dir(0, -1, 0);
    dir.normalise();
    n->setDirection(dir);

    /* END SPOT LIGHT */
    n->attachObject(l);

    // Modify the plane material so that it clips to the light
    // Normally you'd only clip a secondary pass but this is engineered so you
    // can actually see the scissoring effect
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightClipPlanesEnabled(true);

    mCameraNode->setPosition(0, 200, 300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);



}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_LightClipPlanesMoreLights::PlayPen_LightClipPlanesMoreLights()
{
    mInfo["Title"] = "PlayPen_LightClipPlanesMoreLights";
    mInfo["Description"] = "Tests light clip planes with more lights.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_LightClipPlanesMoreLights::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue(0.3, 0.25, 0.2, 0));
    mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_ADDITIVE);
    mSceneMgr->setShadowTextureCount(3);

    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 0;
    MeshManager::getSingleton().createPlane(
        "Myplane",
        TRANSIENT_RESOURCE_GROUP, plane,
        4500, 4500, 100, 100, true, 1, 5, 5, Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );

    MaterialPtr mat = MaterialManager::getSingleton()
                          .getByName("Examples/GrassFloor")
                          ->clone("Myplane/Material", TRANSIENT_RESOURCE_GROUP);

    pPlaneEnt->setMaterial(mat);
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    Real lightRange = 1000;
    Real spotWidth = 300;

    int numLights = 8;
    Real xoff = -numLights * spotWidth * 0.5;

    for (int i = 0; i < numLights; ++i)
    {
        Light* l = mSceneMgr->createLight("l" + StringConverter::toString(i));
        l->setAttenuation(lightRange, 1, 0, 0);
        /* SPOT LIGHT
         */
        // match spot width to groud
        Real spotHeight = lightRange * 0.5;
        SceneNode* n = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3((spotWidth+50)*i + xoff,spotHeight,0));
        l->setType(Light::LT_SPOTLIGHT);
        Radian spotAngle = Math::ATan(spotWidth / spotHeight) * 2;
        l->setSpotlightOuterAngle(spotAngle);
        l->setSpotlightInnerAngle(spotAngle * 0.75);
        Vector3 dir(0, -1, 0);
        dir.normalise();
        n->setDirection(dir, Node::TS_WORLD);

        /* END SPOT LIGHT */
        n->attachObject(l);

        Entity* e = mSceneMgr->createEntity("e" + StringConverter::toString(i), "robot.mesh");
        SceneNode* en = n->createChildSceneNode(Vector3(0, -200, 0));
        en->attachObject(e);
    }

    // Modify the plane material so that it clips to the light on the second pass, post ambient
    Pass* p = mat->getTechnique(0)->getPass(0);
    String texname = p->getTextureUnitState(0)->getTextureName();
    p->removeAllTextureUnitStates();
    p->setIlluminationStage(IS_AMBIENT);
    p->setDiffuse(ColourValue::Black);
    p = mat->getTechnique(0)->createPass();
    p->setIlluminationStage(IS_PER_LIGHT);
    p->setIteratePerLight(true, true);
    //TODO Shouldn't the case below also be tested?
    // p->setIteratePerLight(true, false);
    p->setAmbient(ColourValue::Black);
    p->setLightClipPlanesEnabled(true);
    p->setSceneBlending(SBT_ADD);
    //if (scissortoo)
    //p->setLightScissoringEnabled(true);
    p = mat->getTechnique(0)->createPass();
    p->setIlluminationStage(IS_DECAL);
    p->createTextureUnitState(texname);
    p->setLightingEnabled(false);
    p->setSceneBlending(SBT_MODULATE);

    mCameraNode->setPosition(0, 200, 300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_LightScissoring::PlayPen_LightScissoring()
{
    mInfo["Title"] = "PlayPen_LightScissoring";
    mInfo["Description"] = "Tests light scissoring.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_LightScissoring::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue::White);


    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 0;
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            4500,4500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );

    MaterialPtr mat = MaterialManager::getSingleton()
                          .getByName("Examples/GrassFloor")
                          ->clone("Myplane/Material", TRANSIENT_RESOURCE_GROUP);

    pPlaneEnt->setMaterial(mat);
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    Real lightRange = 100;

    ManualObject* debugSphere = mSceneMgr->createManualObject("debugSphere");
    debugSphere->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_STRIP);
    for (int i = 0; i <= 20; ++i)
    {
        Vector3 basePos(lightRange, 0, 0);
        Quaternion quat;
        quat.FromAngleAxis(Radian(((float)i/(float)20)*Math::TWO_PI), Vector3::UNIT_Y);
        basePos = quat * basePos;
        debugSphere->position(basePos);
    }
    for (int i = 0; i <= 20; ++i)
    {
        Vector3 basePos(lightRange, 0, 0);
        Quaternion quat;
        quat.FromAngleAxis(Radian(((float)i/(float)20)*Math::TWO_PI), Vector3::UNIT_Z);
        basePos = quat * basePos;
        debugSphere->position(basePos);
    }
    debugSphere->end();

    ManualObject* debugSphere2 = mSceneMgr->createManualObject("debugSphere2");
    debugSphere2->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_STRIP);
    for (int i = 0; i <= 20; ++i)
    {
        Vector3 basePos(lightRange, 0, 0);
        Quaternion quat;
        quat.FromAngleAxis(Radian(((float)i/(float)20)*Math::TWO_PI), Vector3::UNIT_Y);
        basePos = quat * basePos;
        debugSphere2->position(basePos);
    }
    for (int i = 0; i <= 20; ++i)
    {
        Vector3 basePos(lightRange, 0, 0);
        Quaternion quat;
        quat.FromAngleAxis(Radian(((float)i/(float)20)*Math::TWO_PI), Vector3::UNIT_Z);
        basePos = quat * basePos;
        debugSphere2->position(basePos);
    }
    debugSphere2->end();

    Light* l = mSceneMgr->createLight("l1");
    l->setAttenuation(lightRange, 1, 0, 0);
    SceneNode* n = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,95,0));
    n->attachObject(debugSphere);
    n->attachObject(l);

    Light* l2 = mSceneMgr->createLight("l2");
    l2->setAttenuation(lightRange, 1, 0, 0);
    SceneNode* n2 = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(100,50,0));
    n2->attachObject(debugSphere2);
    n2->attachObject(l2);

    // Modify the plane material so that it clips to the light
    // Normally you'd only clip a secondary pass but this is engineered so you
    // can actually see the scissoring effect
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightScissoringEnabled(true);

    mCameraNode->setPosition(0, 200, 300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_LiSPSM::PlayPen_LiSPSM()
{
    mInfo["Title"] = "PlayPen_LiSPSM";
    mInfo["Description"] = "Tests light-space shadow mapping camera setup.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_LiSPSM::cleanupContent()
{
    clearDebugTextureOverlays();
}
//----------------------------------------------------------------------------

void PlayPen_LiSPSM::setupContent()
{
    SceneNode* mTestNode[10];

    mSceneMgr->setShadowTextureSize(1024);
    mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE);

    //FocusedShadowCameraSetup* lispsmSetup = new FocusedShadowCameraSetup();
    LiSPSMShadowCameraSetup* lispsmSetup = new LiSPSMShadowCameraSetup();
    lispsmSetup->setOptimalAdjustFactor(2);
    mSceneMgr->setShadowCameraSetup(ShadowCameraSetupPtr(lispsmSetup));

    mSceneMgr->setShadowFarDistance(3000);
    mSceneMgr->setShadowColour(ColourValue(0.35, 0.35, 0.35));
    mSceneMgr->setAmbientLight(ColourValue(0.3, 0.3, 0.3));

    OrientedLightPtr mLight = mSceneMgr->createLight("MainLight");
    mLight->setType(Light::LT_DIRECTIONAL);
    Vector3 vec(-1,-1,0);
    vec.normalise();
    mLight->setDirection(vec);

    mTestNode[1] = mSceneMgr->getRootSceneNode()->createChildSceneNode();


    Entity* pEnt;
    pEnt = mSceneMgr->createEntity( "1", "robot.mesh" );
    //pEnt->setRenderingDistance(100);
    AnimationState* mAnimState = pEnt->getAnimationState("Walk");
    mAnimState->setEnabled(true);
    mAnimStateList.push_back(mAnimState);
    //pEnt->setMaterialName("2 - Default");
    mTestNode[1]->attachObject( pEnt );
    mTestNode[1]->translate(0,-100,0);

    pEnt = mSceneMgr->createEntity( "3", "knot.mesh" );
    mTestNode[2] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-200, 0, -200));
    mTestNode[2]->attachObject( pEnt );

    createRandomEntityClones(pEnt, 20, Vector3(-1000,0,-1000), Vector3(1000,0,1000), mSceneMgr);

    // Transparent object (can force cast shadows)
    pEnt = mSceneMgr->createEntity( "3.5", "knot.mesh" );
    MaterialPtr tmat = MaterialManager::getSingleton().create(
        "TestAlphaTransparency",
        TRANSIENT_RESOURCE_GROUP);
    tmat->setTransparencyCastsShadows(true);
    Pass* tpass = tmat->getTechnique(0)->getPass(0);
    tpass->setAlphaRejectSettings(CMPF_GREATER, 150);
    tpass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
    tpass->createTextureUnitState("gras_02.png");
    tpass->setCullingMode(CULL_NONE);

    pEnt->setMaterialName("TestAlphaTransparency");
    mTestNode[3] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(350, 0, -200));
    mTestNode[3]->attachObject( pEnt );

    pEnt = mSceneMgr->createEntity( "4", "knot.mesh" );
    mTestNode[2] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(100, 0, 200));
    mTestNode[2]->attachObject( pEnt );

    mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");

    MovablePlane movablePlane = MovablePlane(Vector3::UNIT_Y, 100);
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, movablePlane,
                                            2500,2500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt;
    pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    addTextureShadowDebugOverlay(1, mSceneMgr);


    mCameraNode->setPosition(0, 1000, 500);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);
    mCamera->setFarClipDistance(10000);


}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------


static void createRandomEntityClones(Entity* ent, size_t cloneCount,
                              const Vector3& min, const Vector3& max, SceneManager* mgr)
{
    Entity *cloneEnt;
    for (size_t n = 0; n < cloneCount; ++n)
    {
        // Create a new node under the root.
        SceneNode* node = mgr->createSceneNode();
        // Random translate.
        Vector3 nodePos;
        nodePos.x = Math::RangeRandom(min.x, max.x);
        nodePos.y = Math::RangeRandom(min.y, max.y);
        nodePos.z = Math::RangeRandom(min.z, max.z);
        node->setPosition(nodePos);
        mgr->getRootSceneNode()->addChild(node);
        cloneEnt = ent->clone(ent->getName() + "_clone" + StringConverter::toString(n));
        // Attach to new node.
        node->attachObject(cloneEnt);

    }
}

PlayPen_LotsAndLotsOfEntities::PlayPen_LotsAndLotsOfEntities()
{
    mInfo["Title"] = "PlayPen_LotsAndLotsOfEntities";
    mInfo["Description"] = "Tests setting up and rendering a lot of entities.";
    addScreenshotFrame(3);// only go a couple frames, this one is slow (and static)
}
//----------------------------------------------------------------------------

void PlayPen_LotsAndLotsOfEntities::setupContent()
{
    // Set ambient light.
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

    // Create a point light.
    OrientedLightPtr l = mSceneMgr->createLight("MainLight");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(-Vector3::UNIT_Y);

    // Create a set of random cubes.
    Entity* ent = mSceneMgr->createEntity("Cube", "cube.mesh");
    ent->setMaterial(MaterialManager::getSingleton().getDefaultMaterial());
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);
    createRandomEntityClones(ent, 3000, Vector3(-1000,-1000,-1000), Vector3(1000,1000,1000), mSceneMgr);

    //bool val = true;
    //mSceneMgr->setOption("ShowOctree", &val);

    mCameraNode->setPosition(0,0, -4000);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

    // Enable the profiler.
    Profiler* prof = Profiler::getSingletonPtr();
    if (prof)
        prof->setEnabled(true);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_ManualBoneMovement::PlayPen_ManualBoneMovement()
{
    mInfo["Title"] = "PlayPen_ManualBoneMovement";
    mInfo["Description"] = "Tests manually controlling a skeletal animation bone.";
    addScreenshotFrame(50);
}
//----------------------------------------------------------------------------

bool PlayPen_ManualBoneMovement::frameStarted(const FrameEvent& evt)
{
    mBone->yaw(Degree(evt.timeSinceLastFrame*100));
    return true;
}
//----------------------------------------------------------------------------

void PlayPen_ManualBoneMovement::setupContent()
{
    Entity *ent = mSceneMgr->createEntity("robot", "robot.mesh");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);
    mSceneMgr->setAmbientLight(ColourValue(0.8, 0.8, 0.8));

    //ent->setMaterialName("Examples/Rocky");

    SkeletonInstance* skel = ent->getSkeleton();
    Animation* anim = skel->getAnimation("Walk");
    mBone = skel->getBone("Joint10");
    mBone->setManuallyControlled(true);
    anim->destroyNodeTrack(mBone->getHandle());

    //AnimationState* animState = ent->getAnimationState("Walk");
    //animState->setEnabled(true);

    mCameraNode->setPosition(100,50,200);
    mCameraNode->lookAt(Vector3(0, 25, 0), Node::TS_PARENT);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_ManualIlluminationStage::PlayPen_ManualIlluminationStage()
{
    mInfo["Title"] = "PlayPen_ManualIlluminationStage";
    mInfo["Description"] = "Tests manual illumination stages.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_ManualIlluminationStage::setupContent()
{
    // Make this viewport work with shader generator scheme.
    mViewport->setMaterialScheme(MSN_SHADERGEN);

    mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE);
    mSceneMgr->setShadowDirectionalLightExtrusionDistance(1000);

    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.0, 0.0, 0.0));

    Light* mLight = mSceneMgr->createLight("MainLight");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-400,400,-300))->attachObject(mLight);
    mLight->setDiffuseColour(0.9, 0.9, 1);
    mLight->setSpecularColour(0.9, 0.9, 1);
    mLight->setAttenuation(6000,1,0.001,0);

    mLight = mSceneMgr->createLight("Light2");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(300,200,100))->attachObject(mLight);
    mLight->setDiffuseColour(1, 0.6, 0.5);
    mLight->setSpecularColour(0.9, 0.9, 1);
    mLight->setAttenuation(6000,1,0.001,0);

    MeshPtr msh = MeshManager::getSingleton().load("knot.mesh", ASSETS_RESOURCE_GROUP);
    msh->buildTangentVectors();
    Entity* pEnt = mSceneMgr->createEntity( "3.5", "knot.mesh" );
    pEnt->setMaterialName("Examples/OffsetMapping/Specular");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject( pEnt );

    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 100;
    MeshPtr planeMesh = MeshManager::getSingleton().createPlane(
        "Myplane",
        TRANSIENT_RESOURCE_GROUP, plane,
        1500, 1500, 100, 100, true, 1, 15, 15, Vector3::UNIT_Z);
    planeMesh->buildTangentVectors();
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("Examples/OffsetMapping/Specular");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    mCameraNode->setPosition(180, 34, 223);
    mCameraNode->lookAt(Vector3(0, 50, 0), Node::TS_PARENT);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_ManualObject2D::PlayPen_ManualObject2D()
{
    mInfo["Title"] = "PlayPen_ManualObject2D";
    mInfo["Description"] = "Tests 2d manual objects.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_ManualObject2D::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue::White);

    ManualObject* man = mSceneMgr->createManualObject("1");
    man->begin("Examples/OgreLogo");
    man->position( 0.0, 0.0, 0.0);  man->textureCoord( 0, 1 ); man->normal(0, 0, 1);
    man->position( 0.1, 0.0, 0.0);  man->textureCoord( 1, 1 ); man->normal(0, 0, 1);
    man->position( 0.1, 0.1, 0.0);  man->textureCoord( 1, 0 ); man->normal(0, 0, 1);
    man->position( 0.0, 0.1, 0.0);  man->textureCoord( 0, 0 ); man->normal(0, 0, 1);

    man->triangle( 0, 1, 2 );
    man->triangle( 0, 2, 3 );

    man->setRenderQueueGroup(RENDER_QUEUE_OVERLAY - 1);
    man->end();
    man->setUseIdentityProjection(true);
    man->setUseIdentityView(true);
    man->setBoundingBox(AxisAlignedBox::EXTENT_INFINITE);

    SceneNode* sn = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    sn->setScale(5,5,1);
    sn->attachObject(man);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_ManualObjectIndexed::PlayPen_ManualObjectIndexed()
{
    mInfo["Title"] = "PlayPen_ManualObjectIndexed";
    mInfo["Description"] = "Tests indexed manual objects.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_ManualObjectIndexed::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
    Vector3 dir(-1, -1, 0.5);
    dir.normalise();
    OrientedLightPtr l = mSceneMgr->createLight("light1");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(dir);

    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 100;
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            1500,1500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    // Define a 40x40 plane, indexed
    //! [manual_plane_begin]
    Ogre::ManualObject* man = mSceneMgr->createManualObject("test");
    man->begin("Examples/OgreLogo", Ogre::RenderOperation::OT_TRIANGLE_LIST);
    //! [manual_plane_begin]

    //! [manual_plane_vertices]
    man->position(-20, 20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 0);

    man->position(-20, -20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 1);

    man->position(20, -20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(1, 1);

    man->position(20, 20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(1, 0);
    //! [manual_plane_vertices]

    //! [manual_plane_faces]
    man->quad(0, 1, 2, 3);
    //! [manual_plane_faces]

    man->end();

    man->begin("Examples/BumpyMetal");

    // Define a 40x40 plane, indexed
    man->position(-20, 20, 20);
    man->normal(0, 1, 0);
    man->textureCoord(0, 0);

    man->position(20, 20, 20);
    man->normal(0, 1, 0);
    man->textureCoord(0, 1);

    man->position(20, 20, -20);
    man->normal(0, 1, 0);
    man->textureCoord(1, 1);

    man->position(-20, 20, -20);
    man->normal(0, 1, 0);
    man->textureCoord(1, 0);

    man->quad(0, 1, 2, 3);

    //! [manual_plane_end]
    man->end();
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(man);
    //! [manual_plane_end]

    mCameraNode->setPosition(100,100,100);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_ManualObjectIndexedUpdateLarger::PlayPen_ManualObjectIndexedUpdateLarger()
{
    mInfo["Title"] = "PlayPen_ManualObjectIndexedUpdateLarger";
    mInfo["Description"] = "Tests updating indexed manual objects.";
}
//----------------------------------------------------------------------------

void PlayPen_ManualObjectIndexedUpdateLarger::setupContent()
{
    PlayPen_ManualObjectIndexed::setupContent();
    ManualObject* man = mSceneMgr->getManualObject("test");

    man->beginUpdate(0);
    // 1 quad larger
    man->position(-20, 20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 0);

    man->position(-20, -20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 1);

    man->position(20, -20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(1, 1);

    man->position(20, 20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(1, 0);


    man->position(-20, 40, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 0);

    man->position(-20, 20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 1);

    man->position(20, 20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(1, 1);

    man->position(20, 40, 20);
    man->normal(0, 0, 1);
    man->textureCoord(1, 0);

    man->quad(0, 1, 2, 3);
    man->quad(4, 5, 6, 7);

    man->end();

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_ManualObjectIndexedUpdateSmaller::PlayPen_ManualObjectIndexedUpdateSmaller()
{
    mInfo["Title"] = "PlayPen_ManualObjectIndexedUpdateSmaller";
    mInfo["Description"] = "Tests updating indexed manual objects.";
}
//----------------------------------------------------------------------------

void PlayPen_ManualObjectIndexedUpdateSmaller::setupContent()
{
    PlayPen_ManualObjectIndexed::setupContent();
    ManualObject* man = mSceneMgr->getManualObject("test");

    man->beginUpdate(0);
    // 1 tri smaller
    man->position(-20, 20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 0);

    man->position(-20, -20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 1);

    man->position(20, -20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(1, 1);

    man->triangle(0, 1, 2);

    man->end();

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_ManualObjectNonIndexed::PlayPen_ManualObjectNonIndexed()
{
    mInfo["Title"] = "PlayPen_ManualObjectNonIndexed";
    mInfo["Description"] = "Tests non-indexed manual objects.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_ManualObjectNonIndexed::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
    Vector3 dir(-1, -1, 0.5);
    dir.normalise();
    OrientedLightPtr l = mSceneMgr->createLight("light1");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(dir);

    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 100;
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            1500,1500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    ManualObject* man = mSceneMgr->createManualObject("test");

    man->begin("Examples/OgreLogo");
    // Define a 40x40 plane, non-indexed
    man->position(-20, 20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 0);

    man->position(-20, -20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 1);

    man->position(20, 20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(1, 0);

    man->position(-20, -20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 1);

    man->position(20, -20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(1, 1);

    man->position(20, 20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(1, 0);

    man->end();

    man->begin("Examples/BumpyMetal");

    // Define a 40x40 plane, non-indexed
    man->position(-20, 20, 20);
    man->normal(0, 1, 0);
    man->textureCoord(0, 0);

    man->position(20, 20, 20);
    man->normal(0, 1, 0);
    man->textureCoord(0, 1);

    man->position(20, 20, -20);
    man->normal(0, 1, 0);
    man->textureCoord(1, 1);

    man->position(20, 20, -20);
    man->normal(0, 1, 0);
    man->textureCoord(1, 1);

    man->position(-20, 20, -20);
    man->normal(0, 1, 0);
    man->textureCoord(1, 0);

    man->position(-20, 20, 20);
    man->normal(0, 1, 0);
    man->textureCoord(0, 0);

    man->end();


    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(man);
    mCameraNode->setPosition(100,100,100);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_ManualObjectNonIndexedUpdateLarger::PlayPen_ManualObjectNonIndexedUpdateLarger()
{
    mInfo["Title"] = "PlayPen_ManualObjectNonIndexedUpdateLarger";
    mInfo["Description"] = "Tests updating non-indexed manual objects.";
}
//----------------------------------------------------------------------------

void PlayPen_ManualObjectNonIndexedUpdateLarger::setupContent()
{
    PlayPen_ManualObjectNonIndexed::setupContent();
    ManualObject* man = mSceneMgr->getManualObject("test");

    // Redefine but make larger (2 more tri)
    man->beginUpdate(0);

    man->position(-20, 20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 0);

    man->position(-20, -20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 1);

    man->position(20, 20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(1, 0);

    man->position(-20, -20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 1);

    man->position(20, -20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(1, 1);

    man->position(20, 20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(1, 0);


    man->position(-20, 40, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 0);

    man->position(-20, 20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 1);

    man->position(20, 40, 20);
    man->normal(0, 0, 1);
    man->textureCoord(1, 0);

    man->position(-20, 20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(0, 1);

    man->position(20, 20, 20);
    man->normal(0, 0, 1);
    man->textureCoord(1, 1);

    man->position(20, 40, 20);
    man->normal(0, 0, 1);
    man->textureCoord(1, 0);


    man->end();

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_ManualObjectNonIndexedUpdateSmaller::PlayPen_ManualObjectNonIndexedUpdateSmaller()
{
    mInfo["Title"] = "PlayPen_ManualObjectNonIndexedUpdateSmaller";
    mInfo["Description"] = "Tests updating non-indexed manual objects.";
}
//----------------------------------------------------------------------------

void PlayPen_ManualObjectNonIndexedUpdateSmaller::setupContent()
{
    PlayPen_ManualObjectNonIndexed::setupContent();
    ManualObject* man = mSceneMgr->getManualObject("test");

    // Redefine but make smaller (one tri less)
    man->beginUpdate(0);
    man->position(-30, 30, 30);
    man->normal(0, 0, 1);
    man->textureCoord(0, 0);

    man->position(-30, -30, 30);
    man->normal(0, 0, 1);
    man->textureCoord(0, 1);

    man->position(90, 30, 30);
    man->normal(0, 0, 1);
    man->textureCoord(1, 0);


    man->end();

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_MaterialSchemes::PlayPen_MaterialSchemes()
{
    mInfo["Title"] = "PlayPen_MaterialSchemes";
    mInfo["Description"] = "Tests material scehemes in viewports.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_MaterialSchemes::setupContent()
{

    Entity *ent = mSceneMgr->createEntity("robot", "robot.mesh");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);
    mSceneMgr->setAmbientLight(ColourValue(0.8, 0.8, 0.8));

    MaterialPtr mat = MaterialManager::getSingleton().create("schemetest",
                                                             TRANSIENT_RESOURCE_GROUP);
    // default scheme
    mat->getTechnique(0)->getPass(0)->createTextureUnitState("GreenSkin.jpg");

    Technique* t = mat->createTechnique();
    t->setSchemeName("newscheme");
    t->createPass()->createTextureUnitState("rockwall.tga");
    ent->setMaterialName("schemetest");

#ifdef OGRE_BUILD_COMPONENT_RTSHADERSYSTEM
    // force create shaders for non default scheme
    t->setSchemeName("newscheme_tmp");
    RTShader::ShaderGenerator& rtShaderGen = RTShader::ShaderGenerator::getSingleton();
    rtShaderGen.createShaderBasedTechnique(*mat, "newscheme_tmp", "newscheme");
    rtShaderGen.validateMaterial("newscheme", *mat);
#endif

    // create a second viewport using alternate scheme
    Viewport* vp = mWindow->addViewport(mCamera, 1, 0.75, 0, 0.25, 0.25);
    vp->setMaterialScheme("newscheme");
    vp->setOverlaysEnabled(false);

    mCameraNode->setPosition(0,75,200);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_MaterialSchemesListener::PlayPen_MaterialSchemesListener()
{
    mInfo["Title"] = "PlayPen_MaterialSchemesListener";
    mInfo["Description"] = "Tests material scheme listener.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

class TestMatMgrListener : public MaterialManager::Listener
{
public:
    TestMatMgrListener() : mTech(0) {}
    Technique* mTech;


    Technique* handleSchemeNotFound(unsigned short schemeIndex,
                                    const String& schemeName, Material* originalMaterial, unsigned short lodIndex,
                                    const Renderable* rend) override
    {
        return mTech;
    }
};

TestMatMgrListener schemeListener;

void PlayPen_MaterialSchemesListener::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue(0.8, 0.8, 0.8));

    Entity *ent = mSceneMgr->createEntity("robot", "robot.mesh");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);
    
    // create a second viewport using alternate scheme
    // notice it's not defined in a technique
    Viewport* vp = mWindow->addViewport(mCamera, 1, 0.75, 0, 0.25, 0.25);
    vp->setMaterialScheme("newscheme");
    vp->setOverlaysEnabled(false);

    MaterialPtr mat = MaterialManager::getSingleton().create("schemetest",
                                                             TRANSIENT_RESOURCE_GROUP);
    // default scheme
    mat->getTechnique(0)->getPass(0)->createTextureUnitState("GreenSkin.jpg");

    schemeListener.mTech = mat->getTechnique(0);
    MaterialManager::getSingleton().addListener(&schemeListener);

    mCameraNode->setPosition(0, 75, 200);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_MaterialSchemesWithLOD::PlayPen_MaterialSchemesWithLOD()
{
    mInfo["Title"] = "PlayPen_MaterialSchemesWithLOD";
    mInfo["Description"] = "Tests material schemes with LODs.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_MaterialSchemesWithLOD::setupContent()
{

    Entity *ent = mSceneMgr->createEntity("robot", "robot.mesh");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);
    mSceneMgr->setAmbientLight(ColourValue(0.8, 0.8, 0.8));

    MaterialPtr mat = MaterialManager::getSingleton().create("schemetest",
                                                             TRANSIENT_RESOURCE_GROUP);
    // default scheme
    mat->getTechnique(0)->getPass(0)->createTextureUnitState("GreenSkin.jpg");

    // LOD 0, newscheme
    Technique* t = mat->createTechnique();
    t->setSchemeName("newscheme");
    t->createPass()->createTextureUnitState("rockwall.tga");
    ent->setMaterialName("schemetest");

    // LOD 1, default
    t = mat->createTechnique();
    t->setLodIndex(1);
    t->createPass()->createTextureUnitState("Water02.jpg");

    // LOD 1, newscheme
    t = mat->createTechnique();
    t->setLodIndex(1);
    t->createPass()->createTextureUnitState("r2skin.jpg");
    t->setSchemeName("newscheme");

    Material::LodValueList ldl;
    //ldl.push_back(Math::Sqr(500.0f));
    ldl.push_back(150.0f);
    mat->setLodLevels(ldl);


    ent->setMaterialName("schemetest");

    // create a second viewport using alternate scheme
    Viewport* vp = mWindow->addViewport(mCamera, 1, 0.75, 0, 0.25, 0.25);
    vp->setMaterialScheme("newscheme");
    vp->setOverlaysEnabled(false);

    mCameraNode->setPosition(0,90,250);
    //mCameraNode->lookAt(Vector3(Vector3(0, 0, 0)), Node::TS_PARENT);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_MaterialSchemesWithMismatchedLOD::PlayPen_MaterialSchemesWithMismatchedLOD()
{
    mInfo["Title"] = "PlayPen_MaterialSchemesWithMismatchedLOD";
    mInfo["Description"] = "Tests material scehemes in viewports with mismatched LODs.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_MaterialSchemesWithMismatchedLOD::setupContent()
{

    Entity *ent = mSceneMgr->createEntity("robot", "robot.mesh");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);
    mSceneMgr->setAmbientLight(ColourValue(0.8, 0.8, 0.8));

    MaterialPtr mat = MaterialManager::getSingleton().create("schemetest",
                                                             TRANSIENT_RESOURCE_GROUP);
    // default scheme
    mat->getTechnique(0)->getPass(0)->createTextureUnitState("GreenSkin.jpg");

    // LOD 0, newscheme
    Technique* t = mat->createTechnique();
    t->setSchemeName("newscheme");
    t->createPass()->createTextureUnitState("rockwall.tga");
    ent->setMaterialName("schemetest");

    // LOD 1, default
    t = mat->createTechnique();
    t->setLodIndex(1);
    t->createPass()->createTextureUnitState("Water02.jpg");

    // LOD 2, default
    t = mat->createTechnique();
    t->setLodIndex(2);
    t->createPass()->createTextureUnitState("clouds.jpg");

    // LOD 1, newscheme
    t = mat->createTechnique();
    t->setLodIndex(1);
    t->createPass()->createTextureUnitState("r2skin.jpg");
    t->setSchemeName("newscheme");

    // No LOD 2 for newscheme! Should fallback on LOD 1

    Material::LodValueList ldl;
    //ldl.push_back(Math::Sqr(250.0f));
    //ldl.push_back(Math::Sqr(500.0f));
    ldl.push_back(150.0f);
    ldl.push_back(300.0f);
    mat->setLodLevels(ldl);


    ent->setMaterialName("schemetest");

    // create a second viewport using alternate scheme
    Viewport* vp = mWindow->addViewport(mCamera, 1, 0.75, 0, 0.25, 0.25);
    vp->setMaterialScheme("newscheme");
    vp->setOverlaysEnabled(false);

    mCameraNode->setPosition(0,90,350);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

/*PlayPen_MRTCompositorScript::PlayPen_MRTCompositorScript()
  {
  mInfo["Title"] = "PlayPen_MRTCompositorScript";
  mInfo["Description"] = "Tests MRT compositor.";
  addScreenshotFrame(250);
  }
  //----------------------------------------------------------------------------

  void PlayPen_MRTCompositorScript::setupContent()
  {

  Entity* e = mSceneMgr->createEntity("e1", "knot.mesh");
  e->setMaterialName("Ogre/MRTtest/scene");
  mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);
  mCameraNode->setPosition(0, 0, -100);
  mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

  CompositorInstance* compInst =
  CompositorManager::getSingleton().addCompositor(mWindow->getViewport(0), "TestMRT");
  CompositorManager::getSingleton().setCompositorEnabled(mWindow->getViewport(0), "TestMRT", true);

  // Set up debug panels for each of the MRT outputs
  String texName = compInst->getTextureInstanceName("mrt0", 0);
  addTextureDebugOverlay(TextureManager::getSingleton().getByName(texName), 0);
  texName = compInst->getTextureInstanceName("mrt0", 1);
  addTextureDebugOverlay(TextureManager::getSingleton().getByName(texName), 1);
  texName = compInst->getTextureInstanceName("mrt0", 2);
  addTextureDebugOverlay(TextureManager::getSingleton().getByName(texName), 2);
  texName = compInst->getTextureInstanceName("mrt0", 3);
  addTextureDebugOverlay(TextureManager::getSingleton().getByName(texName), 3);
  }*/
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

/*PlayPen_MRT::PlayPen_MRT()
  {
  mInfo["Title"] = "PlayPen_MRT";
  mInfo["Description"] = "Tests MRT.";
  addScreenshotFrame(250);
  }
  //----------------------------------------------------------------------------

  void PlayPen_MRT::setupContent()
  {
  TexturePtr Tex[2];
  MultiRenderTarget* mrtTex;

  Viewport* viewport = mWindow->getViewport(0);
  int width = viewport->getActualWidth();
  int height = viewport->getActualHeight();

  Tex[0] = TextureManager::getSingleton().createManual("diffusemap", TRANSIENT_RESOURCE_GROUP, TEX_TYPE_2D,
  width,height,0,PF_R8G8B8A8,TU_RENDERTARGET);
  Tex[1] = TextureManager::getSingleton().createManual("normalmap",TRANSIENT_RESOURCE_GROUP, TEX_TYPE_2D,
  width,height,0,PF_R8G8B8A8,TU_RENDERTARGET);

  //    assert(Tex[0]->getFormat() == PF_FLOAT16_RGBA);

  mrtTex = Ogre::Root::getSingleton().getRenderSystem()->createMultiRenderTarget("MRT");
  RenderTexture* rTex[2];
  rTex[0] = Tex[0]->getBuffer()->getRenderTarget();
  rTex[1] = Tex[1]->getBuffer()->getRenderTarget();

  rTex[0]->setAutoUpdated(false);
  rTex[1]->setAutoUpdated(false);
  mrtTex->bindSurface(0, rTex[0]);
  mrtTex->bindSurface(1, rTex[1]);
  mrtTex->setAutoUpdated(true);

  Viewport *v = mrtTex->addViewport(mCamera);
  v->setMaterialScheme("MRT");
  v->setClearEveryFrame(true);
  v->setOverlaysEnabled(false);
  v->setSkiesEnabled(false);
  v->setBackgroundColour(ColourValue(0,0,0,0));

  // Create texture overlay here
  Overlay *debugOverlay = OverlayManager::getSingleton().create("Core/DebugOverlay");
  MaterialPtr debugMat = MaterialManager::getSingleton().create("DebugRTTMat1", TRANSIENT_RESOURCE_GROUP);
  debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false);
  TextureUnitState *t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState("normalmap");
  t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
  OverlayContainer *debugPanel = (OverlayContainer *) (OverlayManager::getSingleton().createOverlayElement("Panel","DebugRTTPanel1"));
  debugPanel->_setPosition(0.8,0);
  debugPanel->_setDimensions(0.2,0.3);
  debugPanel->setMaterialName(debugMat->getName());
  debugOverlay->add2D(debugPanel);

  debugMat = MaterialManager::getSingleton().create("DebugRTTMat2", TRANSIENT_RESOURCE_GROUP);
  debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false);
  t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState("diffusemap");
  t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
  debugPanel = (OverlayContainer *) (OverlayManager::getSingleton().createOverlayElement("Panel","DebugRTTPanel2"));
  debugPanel->_setPosition(0.8,0.3);
  debugPanel->_setDimensions(0.2,0.3);
  debugPanel->setMaterialName(debugMat->getName());
  debugOverlay->add2D(debugPanel);
  // Create scene items

  // Create a material to render differently to MRT compared to main viewport
  MaterialPtr mat = MaterialManager::getSingleton().create("MRTTest",
  TRANSIENT_RESOURCE_GROUP);
  // normal technique (0), leave as default
  Technique* mrtTech = mat->createTechnique();
  mrtTech->setSchemeName("MRT");
  Pass* mrtPass = mrtTech->createPass();
  mrtPass->setVertexProgram("DeferredShading/material/hlsl/vs");
  mrtPass->setFragmentProgram("DeferredShading/material/hlsl/ps");
  mrtPass->createTextureUnitState("rockwall.tga");
  mat->load();

  Entity* ent = mSceneMgr->createEntity("knot", "knot.mesh");
  ent->setMaterialName("MRTTest");
  mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);

  mCameraNode->setPosition(0, 0, 200);
  mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);



  }*/
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_MultiSceneManagersSimple::PlayPen_MultiSceneManagersSimple()
{
    mInfo["Title"] = "PlayPen_MultiSceneManagersSimple";
    mInfo["Description"] = "Tests multiple scene managers.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_MultiSceneManagersSimple::setupContent()
{
    // Create a secondary scene manager with it's own camera
    SceneManager* sm2 = Root::getSingleton().createSceneManager();
    Light* l = sm2->createLight("l2");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(100, 50, -100))->attachObject(l);
    l->setDiffuseColour(ColourValue::Green);
    // l->setDiffuseColour(ColourValue::Red);
    sm2->setAmbientLight(ColourValue(0.2, 0.2, 0.2));
    // sm2->setAmbientLight(ColourValue(1, 1, 1));
    Entity* ent = sm2->createEntity("knot2", "knot.mesh");
    // Entity* ent = sm2->createEntity("head", "ogrehead.mesh");
    sm2->getRootSceneNode()->createChildSceneNode()->attachObject(ent);
    Camera* camera2 = sm2->createCamera("cam2");
    SceneNode* camNode2 = sm2->getRootSceneNode()->createChildSceneNode();
    camNode2->attachObject(camera2);
    camNode2->setPosition(0, 0, -500);
    camNode2->lookAt(Vector3::ZERO, Node::TS_PARENT);

    Viewport* vp = mWindow->addViewport(camera2, 1, 0.67, 0, 0.33, 0.25);
    vp->setOverlaysEnabled(false);
    vp->setBackgroundColour(ColourValue(1,0,0));

    // Use original SM for normal scene
    l = mSceneMgr->createLight("l"); // note same name, will work since different SM
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(100, 50, -100))->attachObject(l);
    l->setDiffuseColour(ColourValue::Red);
    mSceneMgr->setAmbientLight(ColourValue(0.2, 0.2, 0.2));
    ent = mSceneMgr->createEntity("head", "ogrehead.mesh");
    // ent = mSceneMgr->createEntity("knot", "knot.mesh");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);
    mCameraNode->setPosition(0, 0, 500);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_MultiViewports::PlayPen_MultiViewports()
{
    mInfo["Title"] = "PlayPen_MultiViewports";
    mInfo["Description"] = "Tests multiple viewports.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_MultiViewports::setupContent()
{
    SceneNode* mTestNode[3];

    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

    // Create a point light
    OrientedLightPtr l = mSceneMgr->createLight("MainLight");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(-Vector3::UNIT_Y);

    Entity* pEnt = mSceneMgr->createEntity( "1", "knot.mesh" );
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-30,0,-50))->attachObject(pEnt);

    mTestNode[0] = mSceneMgr->getRootSceneNode()->createChildSceneNode();

    pEnt = mSceneMgr->createEntity( "2", "ogrehead.mesh" );
    mTestNode[0]->attachObject( pEnt );
    mTestNode[0]->translate(0, 0, 200);

    Ogre::Frustum* frustum = new Frustum();
    //frustum->setVisible(true);
    frustum->setFarClipDistance(5000);
    frustum->setNearClipDistance(100);
    mTestNode[0]->attachObject(frustum);

    Viewport* vp = mWindow->addViewport(mCamera, 1, 0.5, 0.5, 0.5, 0.5);
    vp->setOverlaysEnabled(false);
    vp->setBackgroundColour(ColourValue(1,0,0));

    mCameraNode->setPosition(0,0,500);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_NegativeScale::PlayPen_NegativeScale()
{
    mInfo["Title"] = "PlayPen_NegativeScale";
    mInfo["Description"] = "Tests negative scaling.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_NegativeScale::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue(0.2, 0.2, 0.2));
    Light* l = mSceneMgr->createLight("l1");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(500, 500, 200))->attachObject(l);
    l->setDiffuseColour(ColourValue::White);

    //mSceneMgr->setFlipCullingOnNegativeScale(false);

    Entity *e = mSceneMgr->createEntity("1", "knot.mesh");

    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);

    // one reflection
    e = mSceneMgr->createEntity("2", "knot.mesh");
    SceneNode* n = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    n->translate(-200, 0, 0);
    n->scale(-1, 1, 1);
    n->attachObject(e);

    // three reflections - will need flipping
    e = mSceneMgr->createEntity("3", "knot.mesh");
    n = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    n->translate(200, 0, 0);
    n->scale(-1, -1, -1);
    n->attachObject(e);

    // two reflections - won't need flipping
    e = mSceneMgr->createEntity("4", "knot.mesh");
    n = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    n->translate(400, 0, 0);
    n->scale(-1, 1, -1);
    n->attachObject(e);

    mWindow->getViewport(0)->setBackgroundColour(ColourValue::Red);

    mCameraNode->setPosition(0,0,300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_NormalMapMirroredUVs::PlayPen_NormalMapMirroredUVs()
{
    mInfo["Title"] = "PlayPen_NormalMapMirroredUVs";
    mInfo["Description"] = "Tests mirrored UVs with normal mapping shader.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_NormalMapMirroredUVs::setupContent()
{
    // Make this viewport work with shader generator scheme.
    mViewport->setMaterialScheme(MSN_SHADERGEN);

    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Tests");

    // this mesh has been generated with 4-component tangents, including a parity in w
    Entity* e = mSceneMgr->createEntity("2", "testmirroreduvmesh.mesh");
    e->setMaterialName("Examples/BumpMapping/MultiLightTangentParity");
    // here's what it looks like without the parity
    // e->setMaterialName("Examples/BumpMapping/MultiLight");

    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);

    Light* l = mSceneMgr->createLight("3");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(1000,500,1000))->attachObject(l);

    mCameraNode->setPosition(0,200,50);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

    mSceneMgr->setAmbientLight(ColourValue(0.2, 0.2, 0.2));
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_Ortho::PlayPen_Ortho()
{
    mInfo["Title"] = "PlayPen_Ortho";
    mInfo["Description"] = "Tests orthographic rendering.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_Ortho::setupContent()
{
    SceneNode* mTestNode[3];

    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.0, 0.0, 0.0));

    // Create a point light
    Light* l = mSceneMgr->createLight("MainLight");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(800,600,0))->attachObject(l);

    mTestNode[0] = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    mSceneMgr->getRootSceneNode()->createChildSceneNode();

    Entity* pEnt = mSceneMgr->createEntity( "3", "knot.mesh" );
    mTestNode[1] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-200, 0, -200));
    mTestNode[1]->attachObject( pEnt );

    pEnt = mSceneMgr->createEntity( "4", "knot.mesh" );
    mTestNode[2] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(100, 0, 200));
    mTestNode[2]->attachObject( pEnt );


    mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");


    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 100;
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            1500,1500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    mCameraNode->setFixedYawAxis(false);
    mCamera->setProjectionType(PT_ORTHOGRAPHIC);
    mCameraNode->setPosition(0,10000,0);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);
    mCamera->setNearClipDistance(1000);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_PointSprites::PlayPen_PointSprites()
{
    mInfo["Title"] = "PlayPen_PointSprites";
    mInfo["Description"] = "Tests point sprites.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_PointSprites::setupContent()
{
    MaterialPtr mat = MaterialManager::getSingleton().create("spriteTest1",
                                                             TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setPointSpritesEnabled(true);
    p->createTextureUnitState("flare.png");
    p->setLightingEnabled(false);
    p->setDepthWriteEnabled(false);
    p->setSceneBlending(SBT_ADD);
    p->setPointAttenuation(true);
    p->setPointSize(3);
    p->setVertexColourTracking(TVC_DIFFUSE);

    ManualObject* man = mSceneMgr->createManualObject("man");
    man->begin("spriteTest1", RenderOperation::OT_POINT_LIST);

    for (size_t i = 0; i < 1000; ++i)
    {
        man->position(Math::SymmetricRandom() * 500,
                      Math::SymmetricRandom() * 500,
                      Math::SymmetricRandom() * 500);
        man->colour(Math::RangeRandom(0.5f, 1.0f),
                    Math::RangeRandom(0.5f, 1.0f), Math::RangeRandom(0.5f, 1.0f));
    }

    // for (size_t i = 0; i < 20; ++i)
    // {
    //     for (size_t j = 0; j < 20; ++j)
    //     {
    //         for (size_t k = 0; k < 20; ++k)
    //         {
    //             if (rand()%10 == 0)
    //                 man->position(i * 30, j * 30, k * 30);
    //         }
    //     }
    // }

    man->end();
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(man);

    mCameraNode->setPosition(0,0,1000);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_Projection::PlayPen_Projection()
{
    mInfo["Title"] = "PlayPen_Projection";
    mInfo["Description"] = "Tests projection.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_Projection::setupContent()
{
    SceneNode* mTestNode[3];

    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

    // Create a point light
    OrientedLightPtr l = mSceneMgr->createLight("MainLight");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(-Vector3::UNIT_Y);

    Entity* pEnt;
    //pEnt = mSceneMgr->createEntity( "1", "knot.mesh" );
    //mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-30,0,-50))->attachObject(pEnt);
    //pEnt->setMaterialName("Examples/OgreLogo");

    // Define a floor plane mesh
    Plane p;
    p.normal = Vector3::UNIT_Z;
    p.d = 200;
    MeshManager::getSingleton().createPlane("WallPlane",
                                            TRANSIENT_RESOURCE_GROUP,
                                            p,1500,1500,1,1,true,1,5,5,Vector3::UNIT_Y);
    pEnt = mSceneMgr->createEntity( "5", "WallPlane" );
    pEnt->setMaterialName("Examples/OgreLogo");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pEnt);


    mTestNode[0] = mSceneMgr->getRootSceneNode()->createChildSceneNode();

    //pEnt = mSceneMgr->createEntity( "2", "ogrehead.mesh" );
    //mTestNode[0]->attachObject( pEnt );
    mTestNode[0]->translate(0, 0, 750);

    Ogre::Frustum* frustum = new Frustum();
    frustum->setVisible(true);
    frustum->setFarClipDistance(5000);
    frustum->setNearClipDistance(200);
    frustum->setAspectRatio(1);
    frustum->setProjectionType(PT_ORTHOGRAPHIC);
    mTestNode[0]->attachObject(frustum);

    // Hook the frustum up to the material
    MaterialPtr mat = MaterialManager::getSingleton().getByName("Examples/OgreLogo");
    TextureUnitState *t = mat->getTechnique(0)->getPass(0)->getTextureUnitState(0);
    t->setProjectiveTexturing(true, frustum);
    //t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_ReflectedBillboards::PlayPen_ReflectedBillboards()
{
    mInfo["Title"] = "PlayPen_ReflectedBillboards";
    mInfo["Description"] = "Tests reflected billboards.";
    addScreenshotFrame(175); // needs to run for a bit so there are particles to be reflected...
}
//----------------------------------------------------------------------------

void PlayPen_ReflectedBillboards::setupContent()
{
    Camera* reflectCam = 0;
    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.2, 0.2, 0.2));

    // Create a light
    OrientedLightPtr l = mSceneMgr->createLight("MainLight");
    l->setType(Light::LT_DIRECTIONAL);
    Vector3 dir(0.5, -1, 0);
    dir.normalise();
    l->setDirection(dir);
    l->setDiffuseColour(1.0f, 1.0f, 0.8f);
    l->setSpecularColour(1.0f, 1.0f, 1.0f);


    // Create a prefab plane
    Plane plane;
    plane.d = 0;
    plane.normal = Vector3::UNIT_Y;
    MeshManager::getSingleton().createPlane("ReflectionPlane",
                                            TRANSIENT_RESOURCE_GROUP,
                                            plane, 2000, 2000,
                                            1, 1, true, 1, 1, 1, Vector3::UNIT_Z);
    Entity* planeEnt = mSceneMgr->createEntity( "Plane", "ReflectionPlane" );

    // Attach the rtt entity to the root of the scene
    SceneNode* rootNode = mSceneMgr->getRootSceneNode();
    SceneNode* planeNode = rootNode->createChildSceneNode();

    // Attach both the plane entity, and the plane definition
    planeNode->attachObject(planeEnt);

    mCameraNode->setPosition(-50, 100, 500);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);

    TexturePtr rttTex = TextureManager::getSingleton().createManual("RttTex",
                                                                    TRANSIENT_RESOURCE_GROUP, TEX_TYPE_2D,
                                                                    512, 512, 1, 0, PF_R8G8B8, TU_RENDERTARGET);
    {
        reflectCam = mSceneMgr->createCamera("ReflectCam");
        reflectCam->setNearClipDistance(mCamera->getNearClipDistance());
        reflectCam->setFarClipDistance(mCamera->getFarClipDistance());
        reflectCam->setAspectRatio(
            (Real)mWindow->getViewport(0)->getActualWidth() /
            (Real)mWindow->getViewport(0)->getActualHeight());

        SceneNode* reflectCamNode = rootNode->createChildSceneNode();
        reflectCamNode->attachObject(reflectCam);
        reflectCamNode->setPosition(mCameraNode->getPosition());
        reflectCamNode->setOrientation(mCameraNode->getOrientation());

        Viewport *v = rttTex->getBuffer()->getRenderTarget()->addViewport( reflectCam );
        v->setClearEveryFrame( true );
        v->setBackgroundColour( ColourValue::Black );

        MaterialPtr mat = MaterialManager::getSingleton().create("RttMat",
                                                                 TRANSIENT_RESOURCE_GROUP);
        mat->getTechnique(0)->getPass(0)->createTextureUnitState("RustedMetal.jpg");
        TextureUnitState* t = mat->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex");
        // Blend with base texture
        t->setColourOperationEx(LBX_BLEND_MANUAL, LBS_TEXTURE, LBS_CURRENT, ColourValue::White,
                                ColourValue::White, 0.25);
        t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
        t->setProjectiveTexturing(true, reflectCam);

        // set up linked reflection
        reflectCam->enableReflection(plane);
        // Also clip
        reflectCam->enableCustomNearClipPlane(plane);
    }

    // Give the plane a texture
    planeEnt->setMaterialName("RttMat");


    // point billboards
    ParticleSystem* pSys2 = mSceneMgr->createParticleSystem("fountain1",
                                                            "Examples/Smoke");
    // Point the fountain at an angle
    SceneNode* fNode = static_cast<SceneNode*>(rootNode->createChild());
    fNode->attachObject(pSys2);

    // oriented_self billboards
    ParticleSystem* pSys3 = mSceneMgr->createParticleSystem("fountain2",
                                                            "Examples/PurpleFountain");
    // Point the fountain at an angle
    fNode = rootNode->createChildSceneNode();
    fNode->translate(-200,-100,0);
    fNode->rotate(Vector3::UNIT_Z, Degree(-20));
    fNode->attachObject(pSys3);



    // oriented_common billboards
    ParticleSystem* pSys4 = mSceneMgr->createParticleSystem("rain",
                                                            "Examples/Rain");
    SceneNode* rNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    rNode->translate(0,1000,0);
    rNode->attachObject(pSys4);
    // Fast-forward the rain so it looks more natural
    pSys4->fastForward(5);


}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_ReinitialiseEntityAlteredMesh::PlayPen_ReinitialiseEntityAlteredMesh()
{
    mInfo["Title"] = "PlayPen_ReinitialiseEntityAlteredMesh";
    mInfo["Description"] = "Tests updating an entity while rendering.";
    addScreenshotFrame(100);
    mTimer = 0.5f;
}
//----------------------------------------------------------------------------

bool PlayPen_ReinitialiseEntityAlteredMesh::frameStarted(const FrameEvent& evt)
{
    if(mTimer > 0.f)
    {
        mTimer -= evt.timeSinceLastFrame;
        if(mTimer <= 0.f)
        {
            // Change the mesh, add a new submesh.

            // Load another mesh.
            MeshPtr msh = MeshManager::getSingleton().load(
                "ogrehead.mesh", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
            for (unsigned short e = 0; e < msh->getNumSubMeshes(); ++e)
            {
                SubMesh* sm = msh->getSubMesh(e);
                sm->clone("", mUpdate);
            }
            mTimer = -5.f;
        }
    }

    return true;
}
//----------------------------------------------------------------------------

void PlayPen_ReinitialiseEntityAlteredMesh::setupContent()
{
    // test whether an Entity picks up that Mesh has changed
    // and therefore rebuild SubEntities

    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

    Light* l = mSceneMgr->createLight("l1");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(200, 300, 0))->attachObject(l);

    Ogre::MeshManager::getSingleton().load("knot.mesh",
                                           ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME)->clone("knot_REINIT.mesh");

    Entity* pEnt = mSceneMgr->createEntity("testEnt", "knot_REINIT.mesh");
    mUpdate = pEnt->getMesh().get();

    mSceneMgr->getRootSceneNode()->attachObject(pEnt);

    mCameraNode->setPosition(0,0,200);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_ReloadResources::PlayPen_ReloadResources()
{
    mInfo["Title"] = "PlayPen_ReloadResources";
    mInfo["Description"] = "Tests unloading and reloading resources.";
    addScreenshotFrame(100);
    mReloadTimer = 0.5f;
}
//----------------------------------------------------------------------------

bool PlayPen_ReloadResources::frameStarted(const FrameEvent& evt)
{
    if(mReloadTimer > 0.f)
    {
        mReloadTimer -= evt.timeSinceLastFrame;

        if(mReloadTimer <= 0.f)
        {
            // unload
            Entity* e = mSceneMgr->getEntity("1");
            e->getParentSceneNode()->detachObject("1");
            mSceneMgr->destroyAllEntities();
            ResourceGroupManager::getSingleton().unloadResourceGroup("TestReload");

            // reload
            e = mSceneMgr->createEntity("1", "UniqueModel.MESH");
            mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);

            mReloadTimer = -5.f;
        }
    }
    return true;
}
//----------------------------------------------------------------------------

void PlayPen_ReloadResources::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue::White);

    // get path to test resources
    const Ogre::ResourceGroupManager::LocationList& ll = Ogre::ResourceGroupManager::getSingleton().getResourceLocationList("Tests");
    const Ogre::ResourceGroupManager::ResourceLocation* loc = &ll.front();
    Ogre::String testResourcePath = loc->archive->getName();

    // add a new group
    // Ogre::String meshFilePath = testResourcePath + "/TestReload";
    Ogre::String meshFilePath = testResourcePath + "/Model2";
    Ogre::ResourceGroupManager& resMgr = Ogre::ResourceGroupManager::getSingleton();
       resMgr.createResourceGroup("TestReload", false);
    resMgr.addResourceLocation(meshFilePath, "FileSystem", "TestReload");
    resMgr.initialiseResourceGroup("TestReload");

    MeshManager& mmgr = MeshManager::getSingleton();
    mmgr.load("UniqueModel.MESH", "TestReload");

    Entity* e = mSceneMgr->createEntity("1", "UniqueModel.MESH");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);

    mCameraNode->setPosition(0,0,200);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_RibbonTrail::PlayPen_RibbonTrail()
{
    mInfo["Title"] = "PlayPen_RibbonTrail";
    mInfo["Description"] = "Tests ribbon trail effect.";
    addScreenshotFrame(150);
}
//----------------------------------------------------------------------------

void PlayPen_RibbonTrail::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
    Vector3 dir(-1, -1, 0.5);
    dir.normalise();
    OrientedLightPtr l = mSceneMgr->createLight("light1");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(dir);

    NameValuePairList pairList;
    pairList["numberOfChains"] = "2";
    pairList["maxElements"] = "80";
    RibbonTrail* trail = static_cast<RibbonTrail*>(
        mSceneMgr->createMovableObject("1", "RibbonTrail", &pairList));
    trail->setMaterialName("Examples/LightRibbonTrail");
    trail->setTrailLength(400);
    //mRibbonTrail = trail;


    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(trail);

    // Create 3 nodes for trail to follow
    SceneNode* animNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    animNode->setPosition(0,20,0);
    Animation* anim = mSceneMgr->createAnimation("an1", 10);
    anim->setInterpolationMode(Animation::IM_SPLINE);
    NodeAnimationTrack* track = anim->createNodeTrack(1, animNode);
    TransformKeyFrame* kf = track->createNodeKeyFrame(0);
    kf->setTranslate(Vector3::ZERO);
    kf = track->createNodeKeyFrame(2);
    kf->setTranslate(Vector3(100, 0, 0));
    kf = track->createNodeKeyFrame(4);
    kf->setTranslate(Vector3(200, 0, 300));
    kf = track->createNodeKeyFrame(6);
    kf->setTranslate(Vector3(0, 20, 500));
    kf = track->createNodeKeyFrame(8);
    kf->setTranslate(Vector3(-100, 10, 100));
    kf = track->createNodeKeyFrame(10);
    kf->setTranslate(Vector3::ZERO);

    //testremoveNode = animNode;

    AnimationState* animState = mSceneMgr->createAnimationState("an1");
    animState->setEnabled(true);
    mAnimStateList.push_back(animState);

    trail->addNode(animNode);
    trail->setInitialColour(0, 1.0, 0.8, 0);
    trail->setColourChange(0, 0.5, 0.5, 0.5, 0.5);
    trail->setInitialWidth(0, 5);

    // Add light
    Light* l2 = mSceneMgr->createLight("l2");
    l2->setDiffuseColour(trail->getInitialColour(0));
    animNode->attachObject(l2);

    // Add billboard
    BillboardSet* bbs = mSceneMgr->createBillboardSet("bb", 1);
    bbs->createBillboard(Vector3::ZERO, trail->getInitialColour(0));
    bbs->setMaterialName("Examples/Flare");
    animNode->attachObject(bbs);

    animNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    animNode->setPosition(-50,10,0);
    anim = mSceneMgr->createAnimation("an2", 10);
    anim->setInterpolationMode(Animation::IM_SPLINE);
    track = anim->createNodeTrack(1, animNode);
    kf = track->createNodeKeyFrame(0);
    kf->setTranslate(Vector3::ZERO);
    kf = track->createNodeKeyFrame(2);
    kf->setTranslate(Vector3(-100, 150, -30));
    kf = track->createNodeKeyFrame(4);
    kf->setTranslate(Vector3(-200, 0, 40));
    kf = track->createNodeKeyFrame(6);
    kf->setTranslate(Vector3(0, -150, 70));
    kf = track->createNodeKeyFrame(8);
    kf->setTranslate(Vector3(50, 0, 30));
    kf = track->createNodeKeyFrame(10);
    kf->setTranslate(Vector3::ZERO);

    animState = mSceneMgr->createAnimationState("an2");
    animState->setEnabled(true);
    mAnimStateList.push_back(animState);

    trail->addNode(animNode);
    trail->setInitialColour(1, 0.0, 1.0, 0.4);
    trail->setColourChange(1, 0.5, 0.5, 0.5, 0.5);
    trail->setInitialWidth(1, 5);


    // Add light
    l2 = mSceneMgr->createLight("l3");
    l2->setDiffuseColour(trail->getInitialColour(1));
    animNode->attachObject(l2);

    // Add billboard
    bbs = mSceneMgr->createBillboardSet("bb2", 1);
    bbs->createBillboard(Vector3::ZERO, trail->getInitialColour(1));
    bbs->setMaterialName("Examples/Flare");
    animNode->attachObject(bbs);


    mCameraNode->setPosition(0,0,500);
    //mSceneMgr->showBoundingBoxes(true);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_SerialisedColour::PlayPen_SerialisedColour()
{
    mInfo["Title"] = "PlayPen_SerialisedColour";
    mInfo["Description"] = "Tests serializing mesh color.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_SerialisedColour::setupContent()
{
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
    Vector3 dir(-1, -1, 0.5);
    dir.normalise();
    OrientedLightPtr l = mSceneMgr->createLight("light1");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(dir);

    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 100;
    MeshManager::getSingleton().createPlane(
        "Myplane", TRANSIENT_RESOURCE_GROUP, plane,
        1500, 1500, 10, 10, true, 1, 5, 5, Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    ManualObject* man = mSceneMgr->createManualObject("test");

    MaterialPtr mat = MaterialManager::getSingleton().create(
        "AmbientVertexColourTracking", TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setVertexColourTracking(TVC_AMBIENT);
    p->setLightingEnabled(false);

    man->begin("AmbientVertexColourTracking");
    //TODO Define a 40x40 plane, non-indexed

    // Define a 40x40 plane, indexed
    man->position(-20, 20, 20);
    man->colour(1, 0, 0);

    man->position(-20, -20, 20);
    man->colour(1, 0, 0);

    man->position(20, -20, 20);
    man->colour(1, 0, 0);

    man->position(20, 20, 20);
    man->colour(1, 0, 0);

    man->quad(0, 1, 2, 3);
    man->end();

    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(man);

    MeshPtr mesh = man->convertToMesh("colourtest.mesh");
    MeshSerializer ms;
    ms.exportMesh(mesh.get(), "colourtest.mesh");

    Entity* c = mSceneMgr->createEntity("1", "colourtest.mesh");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(c);

    mCameraNode->setPosition(0,0,120);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_ShadowLod::PlayPen_ShadowLod()
{
    mInfo["Title"] = "PlayPen_ShadowLod";
    mInfo["Description"] = "Tests whether LOD is based on shadow cam or main cam.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_ShadowLod::cleanupContent()
{
    clearDebugTextureOverlays();
}
//----------------------------------------------------------------------------

void PlayPen_ShadowLod::setupContent()
{
    SceneNode* mTestNode[10];

    // Test that LOD is based on main camera, not shadow camera

    mSceneMgr->setShadowTextureSize(1024);
    mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE);

    //FocusedShadowCameraSetup* lispsmSetup = new FocusedShadowCameraSetup();
    //LiSPSMShadowCameraSetup* lispsmSetup = new LiSPSMShadowCameraSetup();
    //lispsmSetup->setOptimalAdjustFactor(1.5);
    //mSceneMgr->setShadowCameraSetup(ShadowCameraSetupPtr(lispsmSetup));

    mSceneMgr->setShadowColour(ColourValue(0.35, 0.35, 0.35));
    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.3, 0.3, 0.3));

    // Directional test
    if (false)
    {
        OrientedLightPtr mLight = mSceneMgr->createLight("MainLight");
        mLight->setType(Light::LT_DIRECTIONAL);
        Vector3 vec(-1,-1,0);
        vec.normalise();
        mLight->setDirection(vec);
    }
    // Spotlight test
    else
    {
        Light* mLight = mSceneMgr->createLight("MainLight");
        mLight->setType(Light::LT_SPOTLIGHT);
        mLight->setAttenuation(10000, 1, 0, 0);
        mLight->setDiffuseColour(1.0, 1.0, 0.8);
        mTestNode[0] = mSceneMgr->getRootSceneNode()->createChildSceneNode();
        mTestNode[0]->setPosition(400,300,0);
        mTestNode[0]->lookAt(Vector3(0,0,0), Node::TS_WORLD);
        mTestNode[0]->attachObject(mLight);
    }

    mTestNode[1] = mSceneMgr->getRootSceneNode()->createChildSceneNode();


    Entity* pEnt;
    pEnt = mSceneMgr->createEntity( "1", "knot.mesh" );
    // rendering distance should also be based on main cam
    //pEnt->setRenderingDistance(100);
    //pEnt->setMaterialName("2 - Default");
    mTestNode[1]->attachObject( pEnt );
    //mTestNode[1]->translate(0,-100,0);
    /*
      pEnt = mSceneMgr->createEntity( "3", "knot.mesh" );
      mTestNode[2] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-200, 0, -200));
      mTestNode[2]->attachObject( pEnt );


      createRandomEntityClones(pEnt, 20, Vector3(-1000,0,-1000), Vector3(1000,0,1000));


      // Transparent object (can force cast shadows)
      pEnt = mSceneMgr->createEntity( "3.5", "knot.mesh" );
      MaterialPtr tmat = MaterialManager::getSingleton().create("TestAlphaTransparency",
      TRANSIENT_RESOURCE_GROUP);
      tmat->setTransparencyCastsShadows(true);
      Pass* tpass = tmat->getTechnique(0)->getPass(0);
      tpass->setAlphaRejectSettings(CMPF_GREATER, 150);
      tpass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
      tpass->createTextureUnitState("gras_02.png");
      tpass->setCullingMode(CULL_NONE);

      pEnt->setMaterialName("TestAlphaTransparency");
      mTestNode[3] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(350, 0, -200));
      mTestNode[3]->attachObject( pEnt );

      MeshPtr msh = MeshManager::getSingleton().load("knot.mesh",
      TRANSIENT_RESOURCE_GROUP);
      msh->buildTangentVectors(VES_TANGENT, 0, 0);
      pEnt = mSceneMgr->createEntity( "4", "knot.mesh" );
      //pEnt->setMaterialName("Examples/BumpMapping/MultiLightSpecular");
      mTestNode[2] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(100, 0, 200));
      mTestNode[2]->attachObject( pEnt );

      mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");
    */


    MovablePlane movablePlane(Vector3::UNIT_Y, 100);
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, movablePlane,
                                            2500,2500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt;
    pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    if (SHADOWTYPE_TEXTURE_MODULATIVE & SHADOWDETAILTYPE_INTEGRATED)
    {
        pPlaneEnt->setMaterialName("Examples/Plane/IntegratedShadows");
    }
    else
    {
        pPlaneEnt->setMaterialName("2 - Default");
    }
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    addTextureShadowDebugOverlay(1, mSceneMgr);


    /*
      ParticleSystem* pSys2 = mSceneMgr->createParticleSystem("smoke",
      "Examples/Smoke");
      mTestNode[4] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-300, -100, 200));
      mTestNode[4]->attachObject(pSys2);
    */

    mCameraNode->setPosition(0, 1000, 500);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);
    mCamera->setFarClipDistance(10000);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_SkeletalAnimation::PlayPen_SkeletalAnimation()
{
    mInfo["Title"] = "PlayPen_SkeletalAnimation";
    mInfo["Description"] = "Tests skeletal animation.";
    addScreenshotFrame(100);
}
//----------------------------------------------------------------------------

void PlayPen_SkeletalAnimation::setupContent()
{
    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
    //mWindow->getViewport(0)->setBackgroundColour(ColourValue::White);



    Entity *ent = mSceneMgr->createEntity("robot", "robot.mesh");
    //ent->setDisplaySkeleton(true);
    // Uncomment the below to test software skinning
    ent->setMaterialName("Examples/Rocky");
    // Add entity to the scene node
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);
    Ogre::AnimationState* mAnimState = ent->getAnimationState("Walk");
    mAnimState->setEnabled(true);

    // Give it a little ambience with lights
    Light* l;
    l = mSceneMgr->createLight("BlueLight");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-200,-80,-100))->attachObject(l);
    l->setDiffuseColour(0.5, 0.5, 1.0);

    l = mSceneMgr->createLight("GreenLight");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,0,-100))->attachObject(l);
    l->setDiffuseColour(0.5, 1.0, 0.5);

    // Position the camera
    mCameraNode->setPosition(200,50,0);
    mCameraNode->lookAt(Vector3(0, 50, 0), Node::TS_PARENT);

    // Report whether hardware skinning is enabled or not
    /*Technique* t = ent->getSubEntity(0)->getTechnique();
      Pass* p = t->getPass(0);
      OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText");
      if (p->hasVertexProgram() &&
      p->getVertexProgram()->isSkeletalAnimationIncluded())
      {
      guiDbg->setCaption("Hardware skinning is enabled");
      }
      else
      {
      guiDbg->setCaption("Software skinning is enabled");
      }*/

    mAnimStateList.push_back(mAnimState);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_SkeletonAnimationOptimise::PlayPen_SkeletonAnimationOptimise()
{
    mInfo["Title"] = "PlayPen_SkeletonAnimationOptimise";
    mInfo["Description"] = "Tests skeletal animation with hardware and software.";
    addScreenshotFrame(100);
}
//----------------------------------------------------------------------------

void PlayPen_SkeletonAnimationOptimise::setupContent()
{
    SceneNode* mTestNode[5];
    mSceneMgr->setShadowTextureSize(512);
    mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_MODULATIVE);
    mSceneMgr->setShadowFarDistance(1500);
    mSceneMgr->setShadowColour(ColourValue(0.35, 0.35, 0.35));
    //mSceneMgr->setShadowFarDistance(800);
    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.3, 0.3, 0.3));

    Light* mLight = mSceneMgr->createLight("MainLight");

    /*/
    // Directional test
    mLight->setType(Light::LT_DIRECTIONAL);
    Vector3 vec(-1,-1,0);
    vec.normalise();
    mLight->setDirection(vec);
    /*/
    // Point test
    mLight->setType(Light::LT_POINT);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0, 200, 0))->attachObject(mLight);
    //*/

    Entity* pEnt;

    // Hardware animation
    pEnt = mSceneMgr->createEntity( "1", "robot.mesh" );
    AnimationState* a = pEnt->getAnimationState("Walk");
    a->setEnabled(true);
    mAnimStateList.push_back(a);
    mTestNode[0] = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    mTestNode[0]->attachObject( pEnt );
    mTestNode[0]->translate(+100,-100,0);

    // Software animation
    pEnt = mSceneMgr->createEntity( "2", "robot.mesh" );
    pEnt->setMaterialName("BaseWhite");
    a = pEnt->getAnimationState("Walk");
    a->setEnabled(true);
    mAnimStateList.push_back(a);

    mTestNode[1] = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    mTestNode[1]->attachObject( pEnt );
    mTestNode[1]->translate(-100,-100,0);


    Plane plane(Vector3::UNIT_Y, -100);
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            1500,1500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt;
    pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    mCameraNode->setPosition(0,0,300);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_SpotlightViewProj::PlayPen_SpotlightViewProj()
{
    mInfo["Title"] = "PlayPen_SpotlightViewProj";
    mInfo["Description"] = "Tests spotlight camera projection.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_SpotlightViewProj::setupContent()
{
    SceneNode* mTestNode[10];
    bool worldViewProj = true;
    // Define programs that use spotlight projection

    String vpStr;
    vpStr =
        "void vp(float4 position : POSITION,\n"
        "out float4 oPosition : POSITION,\n"
        "out float4 oUV : TEXCOORD0,\n";
    if (!worldViewProj)
    {
        vpStr += "uniform float4x4 world,\n"
            "uniform float4x4 spotlightViewProj,\n";
    }
    else
    {
        vpStr += "uniform float4x4 spotlightWorldViewProj,\n";
    }
    vpStr += "uniform float4x4 worldViewProj)\n"
        "{\n"
        "    oPosition = mul(worldViewProj, position);\n";
    if (worldViewProj)
    {
        vpStr += "    oUV = mul(spotlightWorldViewProj, position);\n";
    }
    else
    {
        vpStr += "    float4 worldPos = mul(world, position);\n"
            "    oUV = mul(spotlightViewProj, worldPos);\n";
    }
    vpStr += "}\n";

    String fpStr =
        "void fp(\n"
        "float4 uv : TEXCOORD0,\n"
        "uniform sampler2D tex : register(s0),\n"
        "out float4 oColor : COLOR)\n"
        "{\n"
        "   uv = uv / uv.w;\n"
        "    oColor = tex2D(tex, uv.xy);\n"
        "}\n";

    HighLevelGpuProgramPtr vp = HighLevelGpuProgramManager::getSingleton()
        .createProgram("testvp",
                       TRANSIENT_RESOURCE_GROUP,
                       "cg", GPT_VERTEX_PROGRAM);
    vp->setSource(vpStr);
    vp->setParameter("profiles", "vs_1_1 arbvp1 glslv");
    vp->setParameter("entry_point", "vp");
    vp->load();

    HighLevelGpuProgramPtr fp = HighLevelGpuProgramManager::getSingleton()
        .createProgram("testfp",
                       TRANSIENT_RESOURCE_GROUP,
                       "cg", GPT_FRAGMENT_PROGRAM);
    fp->setSource(fpStr);
    fp->setParameter("profiles", "ps_2_0 arbfp1 glslf");
    fp->setParameter("entry_point", "fp");
    fp->load();

    MaterialPtr mat = MaterialManager::getSingleton().create("TestSpotlightProj",
                                                             TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setVertexProgram("testvp");
    p->getVertexProgramParameters()->setNamedAutoConstant(
        "worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);

    if (worldViewProj)
    {
        p->getVertexProgramParameters()->setNamedAutoConstant(
            "spotlightWorldViewProj", GpuProgramParameters::ACT_SPOTLIGHT_WORLDVIEWPROJ_MATRIX);
    }
    else
    {
        p->getVertexProgramParameters()->setNamedAutoConstant(
            "world", GpuProgramParameters::ACT_WORLD_MATRIX);
        p->getVertexProgramParameters()->setNamedAutoConstant(
            "spotlightViewProj", GpuProgramParameters::ACT_SPOTLIGHT_VIEWPROJ_MATRIX);
    }
    p->setFragmentProgram("testfp");
    p->createTextureUnitState("ogrelogo.png");

    Entity* pEnt;

    // Define a plane mesh, use the above material
    Plane plane;
    plane.normal = Vector3::UNIT_Z;
    plane.d = 200;
    MeshManager::getSingleton().createPlane("WallPlane",
                                            TRANSIENT_RESOURCE_GROUP,
                                            plane,1500,1500,100,100,true,1,5,5,Vector3::UNIT_Y);
    pEnt = mSceneMgr->createEntity( "5", "WallPlane" );
    pEnt->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pEnt);


    mTestNode[0] = mSceneMgr->getRootSceneNode()->createChildSceneNode();

    mTestNode[0]->translate(0, 0, 750);

    Light* spot = mSceneMgr->createLight("l1");
    spot->setType(Light::LT_SPOTLIGHT);

    mTestNode[0]->attachObject(spot);


}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_SRGBtexture::PlayPen_SRGBtexture()
{
    mInfo["Title"] = "PlayPen_SRGBtexture";
    mInfo["Description"] = "Tests sRGB textures.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_SRGBtexture::setupContent()
{
    // NOTE: enable flag only turns on SRGB for texture sampling, you may
    // need to configure the window for the reverse conversion for consistency!
    MaterialPtr mat = MaterialManager::getSingleton().create("testsrgb",
                                                             TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    p->setCullingMode(CULL_NONE);
    TextureUnitState* t = p->createTextureUnitState("ogrelogo.png");
    t->setHardwareGammaEnabled(true);
    Entity *e = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
    e->setMaterialName(mat->getName());
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);
    mWindow->getViewport(0)->setBackgroundColour(ColourValue::Red);

    mCameraNode->setPosition(0,0,300);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_StaticGeometry::PlayPen_StaticGeometry()
{
    mInfo["Title"] = "PlayPen_StaticGeometry";
    mInfo["Description"] = "Tests static geometry.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_StaticGeometry::setupContent()
{
    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0, 0, 0));
    mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_MODULATIVE);

    // Create a point light
    Light* l = mSceneMgr->createLight("MainLight");
    l->setDiffuseColour(0.4, 0.4, 0.4);

    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0, 600, 0))->attachObject(l);
    l->setAttenuation(10000, 1, 0, 0);

    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 0;
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            4500,4500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("Examples/GrassFloor");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    MeshPtr msh = MeshManager::getSingleton().load("ogrehead.mesh", ASSETS_RESOURCE_GROUP);
    msh->buildTangentVectors();

    Entity* e = mSceneMgr->createEntity("1", "ogrehead.mesh");
    e->setMaterialName("BaseWhite");

    StaticGeometry* s = mSceneMgr->createStaticGeometry("bing");
    s->setCastShadows(true);
    s->setRegionDimensions(Vector3(500,500,500));

    Vector3 min(-500,60,-500);
    Vector3 max(500,60,500);
    for (int i = 0; i < 10; ++i)
    {
        Vector3 pos;
        pos.x = Math::RangeRandom(min.x, max.x);
        pos.y = Math::RangeRandom(min.y, max.y);
        pos.z = Math::RangeRandom(min.z, max.z);

        s->addEntity(e, pos);
        Entity* e2 = e->clone("clone" + StringConverter::toString(i));
        mSceneMgr->getRootSceneNode()->createChildSceneNode(pos+Vector3(0,60,0))->attachObject(e2);

    }

    s->build();

    mCameraNode->setPosition(0,400,1200);
    mCameraNode->setDirection(0,-0.3f,-1.2f);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#ifdef OGRE_BUILD_COMPONENT_MESHLODGENERATOR
PlayPen_StaticGeometryWithLOD::PlayPen_StaticGeometryWithLOD()
{
    mInfo["Title"] = "PlayPen_StaticGeometryWithLOD";
    mInfo["Description"] = "Tests static geometry with LODs.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_StaticGeometryWithLOD::setupContent()
{
    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0, 0, 0));

    // Create a point light
    Light* l = mSceneMgr->createLight("MainLight");
    l->setDiffuseColour(0.4, 0.4, 0.4);
    l->setSpecularColour(ColourValue::White);

    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0, 600, 0))->attachObject(l);
    l->setAttenuation(10000, 1, 0, 0);

    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 0;
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            4500,4500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("Examples/GrassFloor");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    MeshPtr msh = MeshManager::getSingleton().load("knot.mesh", ASSETS_RESOURCE_GROUP);
    LodConfig lodConfig(msh);
    lodConfig.createGeneratedLodLevel(1000, 1400, LodLevel::VRM_CONSTANT);
    MeshLodGenerator().generateLodLevels(lodConfig);

    Entity* e = mSceneMgr->createEntity("1", msh->getName());

    StaticGeometry* s = mSceneMgr->createStaticGeometry("bing");
    s->setCastShadows(true);
    s->setRegionDimensions(Vector3(500,500,500));

    Vector3 min(-500,100,-500);
    Vector3 max(500,100,500);
    for (int i = 0; i < 10; ++i)
    {
        Vector3 pos;
        pos.x = Math::RangeRandom(min.x, max.x);
        pos.y = Math::RangeRandom(min.y, max.y);
        pos.z = Math::RangeRandom(min.z, max.z);

        s->addEntity(e, pos);
    }

    s->build();
    msh->freeEdgeList();
    msh->_setLodInfo(1);
    mCameraNode->setPosition(0,400,1200);
    mCameraNode->setDirection(0,-0.3f,-1.2f);
}
#endif
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

// render queues
#define RENDER_QUEUE_OUTLINE_GLOW_OBJECTS    RENDER_QUEUE_MAIN + 1
#define RENDER_QUEUE_OUTLINE_GLOW_GLOWS        RENDER_QUEUE_MAIN + 2
#define RENDER_QUEUE_FULL_GLOW_ALPHA_GLOW    RENDER_QUEUE_MAIN + 3
#define RENDER_QUEUE_FULL_GLOW_GLOW            RENDER_QUEUE_MAIN + 4
#define LAST_STENCIL_OP_RENDER_QUEUE        RENDER_QUEUE_FULL_GLOW_GLOW

// stencil values
#define STENCIL_VALUE_FOR_OUTLINE_GLOW 1
#define STENCIL_VALUE_FOR_FULL_GLOW 2
#define STENCIL_FULL_MASK 0xFFFFFFFF

// a Render queue listener to change the stencil mode
class StencilOpQueueListener : public Ogre::RenderQueueListener
{
public:
    void renderQueueStarted(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& skipThisInvocation) override
    {
        StencilState stencil;
        stencil.enabled = true;
        stencil.compareOp = CMPF_ALWAYS_PASS;
        stencil.referenceValue = STENCIL_VALUE_FOR_OUTLINE_GLOW;
        stencil.depthStencilPassOp = SOP_REPLACE;

        RenderSystem* rendersys = Root::getSingleton().getRenderSystem();

        switch (queueGroupId)
        {
        default:
            return;
        case RENDER_QUEUE_OUTLINE_GLOW_OBJECTS: // outline glow object
            rendersys->clearFrameBuffer(Ogre::FBT_STENCIL);
            break;
        case RENDER_QUEUE_OUTLINE_GLOW_GLOWS: // outline glow
            stencil.compareOp = CMPF_NOT_EQUAL;
            break;
        case RENDER_QUEUE_FULL_GLOW_ALPHA_GLOW: // full glow - alpha glow
            stencil.referenceValue = STENCIL_VALUE_FOR_FULL_GLOW;
            break;
        case RENDER_QUEUE_FULL_GLOW_GLOW: // full glow - glow
            stencil.compareOp = CMPF_EQUAL;
            stencil.referenceValue = STENCIL_VALUE_FOR_FULL_GLOW;
            break;
        }

        rendersys->setStencilState(stencil);
    }

    void renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation) override
    {
        if ( queueGroupId == LAST_STENCIL_OP_RENDER_QUEUE )
        {
            Root::getSingleton().getRenderSystem()->setStencilState(StencilState());
        }
    }

};
//---------------------------------------------------------------------------

PlayPen_StencilGlow::PlayPen_StencilGlow()
    :mStencilListener(0)
{
    mInfo["Title"] = "PlayPen_StencilGlow";
    mInfo["Description"] = "Tests stencil glow effect.";
    addScreenshotFrame(100);
}
//---------------------------------------------------------------------------

PlayPen_StencilGlow::~PlayPen_StencilGlow()
{
    if(mStencilListener)
        delete mStencilListener;
}
//---------------------------------------------------------------------------

void PlayPen_StencilGlow::setupContent(void)
{
    // test media
    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Tests");

    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

    // Create a point light
    Light* l = mSceneMgr->createLight("MainLight");
    // Accept default settings: point light, white diffuse, just set position
    // NB I could attach the light to a SceneNode if I wanted it to move automatically with
    //  other objects, but I don't
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(20,80,50))->attachObject(l);


    // outline glow entity
    Entity *outlineGlowEntity = mSceneMgr->createEntity("outlineGlow", "ogrehead.mesh");
    outlineGlowEntity->setRenderQueueGroup(RENDER_QUEUE_OUTLINE_GLOW_OBJECTS);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(outlineGlowEntity);


    // outline glow entity actual glow
    Ogre::Entity* actualOutlineGlowEntity = outlineGlowEntity->clone(outlineGlowEntity->getName() + "_glow");
    actualOutlineGlowEntity->setRenderQueueGroup(RENDER_QUEUE_OUTLINE_GLOW_GLOWS);
    actualOutlineGlowEntity->setMaterialName("glow");
    Ogre::SceneNode* actualOutlineGlowNode = outlineGlowEntity->getParentSceneNode()->createChildSceneNode("outlineGlowNode");
    actualOutlineGlowNode->attachObject(actualOutlineGlowEntity);


    // normal entity
    Entity *normalOgreEntity = mSceneMgr->createEntity("normalOgreEntity", "ogrehead.mesh");
    Ogre::SceneNode* normalOgreNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    normalOgreNode->attachObject(normalOgreEntity);
    normalOgreNode->setPosition(80, 0, 0);



    // full glow entity
    Entity *fullGlowEntity = mSceneMgr->createEntity("fullGlowEntity", "ogrehead.mesh");
    Ogre::SceneNode* fullGlowNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    fullGlowNode->attachObject(fullGlowEntity);
    fullGlowNode->setPosition(-80, 0, 0);

    // full glow alpha glow
    Ogre::Entity* alphaFullGlowEntity = fullGlowEntity->clone(fullGlowEntity->getName() + "_alphaGlow");
    alphaFullGlowEntity->setRenderQueueGroup(RENDER_QUEUE_FULL_GLOW_ALPHA_GLOW);
    alphaFullGlowEntity->setMaterialName("alpha_glow");
    Ogre::SceneNode* alphaFullGlowNode = fullGlowEntity->getParentSceneNode()->createChildSceneNode("fullGlowAlphaNode");
    alphaFullGlowNode->attachObject(alphaFullGlowEntity);

    // full glow alpha glow
    Ogre::Entity* glowFullGlowEntity = fullGlowEntity->clone(fullGlowEntity->getName() + "_glow");
    glowFullGlowEntity->setRenderQueueGroup(RENDER_QUEUE_FULL_GLOW_GLOW);
    glowFullGlowEntity->setMaterialName("no_depth_check_glow");
    Ogre::SceneNode* glowFullGlowNode = fullGlowEntity->getParentSceneNode()->createChildSceneNode("fullGlowGlowNode");
    glowFullGlowNode->attachObject(glowFullGlowEntity);

    mCameraNode->setPosition(0,0,200);
    mCameraNode->setDirection(0,0,-1);

    mStencilListener = new StencilOpQueueListener();
    mSceneMgr->addRenderQueueListener(mStencilListener);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_StencilShadows::PlayPen_StencilShadows()
{
    mInfo["Title"] = "PlayPen_StencilShadows";
    mInfo["Description"] = "Tests stencil shadows.";
    addScreenshotFrame(20);
}
//----------------------------------------------------------------------------

void PlayPen_StencilShadows::setupContent()
{
    SceneNode* mTestNode[10];

    mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_MODULATIVE);
    //mSceneMgr->setShowDebugShadows(true);
    mSceneMgr->setShadowDirectionalLightExtrusionDistance(1000);
    //mSceneMgr->setShadowColour(ColourValue(0.4, 0.25, 0.25));

    //mSceneMgr->setShadowFarDistance(800);
    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.0, 0.0, 0.0));

    // Point light
    //if(pointLight)
    {
        Light* mLight = mSceneMgr->createLight("MainLight");
        mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-400, 400, -300))->attachObject(mLight);
        mLight->setDiffuseColour(0.9, 0.9, 1);
        mLight->setSpecularColour(0.9, 0.9, 1);
        mLight->setAttenuation(6000, 1, 0.001, 0);
    }
    // Directional light
    //if (directionalLight)
    {
        OrientedLightPtr mLight = mSceneMgr->createLight("Light2");
        Vector3 dir(-1, -1, 0);
        dir.normalise();
        mLight->setType(Light::LT_DIRECTIONAL);
        mLight->setDirection(dir);
        mLight->setDiffuseColour(1, 1, 0.8);
        mLight->setSpecularColour(1, 1, 1);
    }

    mTestNode[0] = mSceneMgr->getRootSceneNode()->createChildSceneNode();

    // Hardware skin
    Entity* pEnt;
    pEnt = mSceneMgr->createEntity( "1", "robot.mesh" );
    AnimationState* anim = pEnt->getAnimationState("Walk");
    anim->setEnabled(true);
    mAnimStateList.push_back(anim);
    mTestNode[0]->attachObject( pEnt );

    // Software skin
    pEnt = mSceneMgr->createEntity( "12", "robot.mesh" );
    anim = pEnt->getAnimationState("Walk");
    anim->setEnabled(true);
    mAnimStateList.push_back(anim);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(100, 0, 0))->attachObject(pEnt);
    pEnt->setMaterialName("Examples/Rocky");

    // test object
    //pEnt = mSceneMgr->createEntity("tst", "building.mesh");
    //mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(300, 0, 0))->attachObject(pEnt);


    // Does not receive shadows
    pEnt = mSceneMgr->createEntity( "3", "knot.mesh" );
    pEnt->setMaterialName("Examples/EnvMappedRustySteel");
    MaterialPtr mat2 = MaterialManager::getSingleton().getByName("Examples/SphereMappedRustySteel");
    mat2->setReceiveShadows(false);
    mTestNode[2] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-200, 0, -200));
    mTestNode[2]->attachObject( pEnt );

    // Transparent object
    pEnt = mSceneMgr->createEntity( "3.5", "knot.mesh" );
    pEnt->setMaterialName("Examples/TransparentTest");
    MaterialPtr mat3 = MaterialManager::getSingleton().getByName("Examples/TransparentTest");
    pEnt->setCastShadows(false);
    mTestNode[3] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(350, 0, -200));
    mTestNode[3]->attachObject( pEnt );

    // User test
    /*
      pEnt = mSceneMgr->createEntity( "3.6", "ogre_male_endCaps.mesh" );
      mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0, 0, 100))->attachObject( pEnt );
    */

    MeshPtr msh = MeshManager::getSingleton().load("knot.mesh", ASSETS_RESOURCE_GROUP);
    msh->buildTangentVectors();
    pEnt = mSceneMgr->createEntity( "4", "knot.mesh" );
    pEnt->setMaterialName("Examples/BumpMapping/MultiLightSpecular");
    mTestNode[2] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(100, 0, 200));
    mTestNode[2]->attachObject( pEnt );

    // controller based material
    pEnt = mSceneMgr->createEntity( "432", "knot.mesh" );
    pEnt->setMaterialName("Examples/TextureEffect2");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(100, 200, 200))->attachObject( pEnt );

    ParticleSystem* pSys2 = mSceneMgr->createParticleSystem("smoke",
                                                            "Examples/Smoke");
    mTestNode[4] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-300, -100, 200));
    mTestNode[4]->attachObject(pSys2);


    mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");


    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 100;
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            1500,1500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    //mCameraNode->setPosition(180, 34, 223);
    //mCamera->setOrientation(Quaternion(0.7265, -0.2064, 0.6304, 0.1791));

    mCameraNode->setPosition(0,0,400);
    mCameraNode->setDirection(0,0,-1);

    // Create a render texture
    /*    TexturePtr rtt = TextureManager::getSingleton().createManual("rtt0",
          TRANSIENT_RESOURCE_GROUP,
          TEX_TYPE_2D, 512, 512, 0, PF_R8G8B8, TU_RENDERTARGET);
          rtt->getBuffer()->getRenderTarget()->addViewport(mCamera);
          // Create an overlay showing the rtt
          MaterialPtr debugMat = MaterialManager::getSingleton().create(
          "DebugRTT", TRANSIENT_RESOURCE_GROUP);
          debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false);
          TextureUnitState *t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState("rtt0");
          t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
          OverlayContainer* debugPanel = (OverlayContainer*)
          (OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/DebugShadowPanel"));
          debugPanel->_setPosition(0.6, 0);
          debugPanel->_setDimensions(0.4, 0.6);
          debugPanel->setMaterialName("DebugRTT");
          Overlay* debugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");
          debugOverlay->add2D(debugPanel);*/


}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_StencilShadowsMixedOpSubMeshes::PlayPen_StencilShadowsMixedOpSubMeshes()
{
    mInfo["Title"] = "PlayPen_StencilShadowsMixedOpSubMeshes";
    mInfo["Description"] = "Tests mixed operation submeshes.";
    addScreenshotFrame(20);
}
//----------------------------------------------------------------------------

void PlayPen_StencilShadowsMixedOpSubMeshes::setupContent()
{
    mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_MODULATIVE);
    //mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE);
    //mSceneMgr->setShowDebugShadows(true);
    mSceneMgr->setShadowDirectionalLightExtrusionDistance(1000);

    //mSceneMgr->setShadowFarDistance(800);
    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.0, 0.0, 0.0));

    Light* mLight;

    // Point light
    //if(pointLight)
    //{
    mLight = mSceneMgr->createLight("MainLight");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-400,400,-300))->attachObject(mLight);
    mLight->setDiffuseColour(0.9, 0.9, 1);
    mLight->setSpecularColour(0.9, 0.9, 1);
    mLight->setAttenuation(6000,1,0.001,0);
    //}
    // Directional light
    //if (directionalLight)
    //{
    /*mLight = mSceneMgr->createLight("Light2");
      Vector3 dir(-1,-1,0);
      dir.normalise();
      mLight->setType(Light::LT_DIRECTIONAL);
      mLight->setDirection(dir);
      mLight->setDiffuseColour(1, 1, 0.8);
      mLight->setSpecularColour(1, 1, 1);*/
    //}

    mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");


    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 100;
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            1500,1500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("2 - Default");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    //mCameraNode->setPosition(180, 34, 223);
    //mCamera->setOrientation(Quaternion(0.7265, -0.2064, 0.6304, 0.1791));


    ManualObject* man = mSceneMgr->createManualObject("testMO_");
    man->begin("2 - Default");
    man->position(0, 200, 0);
    man->position(0, 50, 100);
    man->position(100, 50, -100);
    man->position(-100, 50, -100);
    man->triangle(0, 1, 2);
    man->triangle(0, 2, 3);
    man->triangle(0, 3, 1);
    man->end();
    man->begin("2 - Default", RenderOperation::OT_LINE_STRIP);
    man->position(0, 200, 0);
    man->position(50, 250, 0);
    man->position(200, 300, 0);
    man->index(0);
    man->index(1);
    man->index(2);
    man->end();
    MeshPtr msh = man->convertToMesh("testMO.mesh_2");

    Entity* e = mSceneMgr->createEntity("34", "testMO.mesh_2");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(e);

    mCameraNode->setPosition(100,320,600);
    mCameraNode->lookAt(Vector3(0, 120, 0), Node::TS_PARENT);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_SubEntityVisibility::PlayPen_SubEntityVisibility()
{
    mInfo["Title"] = "PlayPen_SubEntityVisibility";
    mInfo["Description"] = "Tests sub entity visibility settings.";
    addScreenshotFrame(250);
}
//----------------------------------------------------------------------------

void PlayPen_SubEntityVisibility::setupContent()
{
    SceneNode* mTestNode[5];
    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

    // Create a point light
    OrientedLightPtr l = mSceneMgr->createLight("MainLight");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(-Vector3::UNIT_Y);

    mTestNode[0] = (SceneNode*)mSceneMgr->getRootSceneNode()->createChild();

    Entity* pEnt = mSceneMgr->createEntity( "1", "ogrehead.mesh" );
    mTestNode[0]->attachObject( pEnt );

    pEnt->getSubEntity(1)->setVisible(false);

    mCameraNode->setPosition(0,0,125);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------


PlayPen_TextureShadows::PlayPen_TextureShadows()
{
    mInfo["Title"] = "PlayPen_TextureShadows";
    mInfo["Description"] = "Tests texture shadows.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_TextureShadows::cleanupContent()
{
    clearDebugTextureOverlays();
}
//----------------------------------------------------------------------------

void PlayPen_TextureShadows::setupContent()
{
    SceneNode* mTestNode[10];

    mSceneMgr->setShadowTextureSize(1024);
    mSceneMgr->setShadowTextureCount(1);
    //mSceneMgr->setShadowTechnique(tech);
    mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE);

    //FocusedShadowCameraSetup* lispsmSetup = new FocusedShadowCameraSetup();
    //LiSPSMShadowCameraSetup* lispsmSetup = new LiSPSMShadowCameraSetup();
    //lispsmSetup->setOptimalAdjustFactor(1.5);
    //mSceneMgr->setShadowCameraSetup(ShadowCameraSetupPtr(lispsmSetup));

    mSceneMgr->setShadowFarDistance(1000);
    mSceneMgr->setShadowColour(ColourValue(0.35, 0.35, 0.35));
    //mSceneMgr->setShadowFarDistance(800);
    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.3, 0.3, 0.3));

    OrientedLightPtr mLight = mSceneMgr->createLight("MainLight");


    // Directional test
    //if (directional)
    //{
    mLight->setType(Light::LT_DIRECTIONAL);
    Vector3 vec(-1,-1,0);
    vec.normalise();
    mLight->setDirection(vec);
    //}
    // Spotlight test
    /*else
      {
      mLight->setType(Light::LT_SPOTLIGHT);
      mLight->setAttenuation(1500, 1, 0, 0);
      mLight->setDiffuseColour(1.0, 1.0, 0.8);
      mTestNode[0] = mSceneMgr->getRootSceneNode()->createChildSceneNode();
      mTestNode[0]->setPosition(800,600,0);
      mTestNode[0]->lookAt(Vector3(0,0,0), Node::TS_WORLD, Vector3::UNIT_Z);
      mTestNode[0]->attachObject(mLight);
      }*/

    mTestNode[1] = mSceneMgr->getRootSceneNode()->createChildSceneNode();


    Entity* pEnt;
    pEnt = mSceneMgr->createEntity( "1", "robot.mesh" );
    //pEnt->setRenderingDistance(100);
    AnimationState* mAnimState = pEnt->getAnimationState("Walk");
    mAnimState->setEnabled(true);
    mAnimStateList.push_back(mAnimState);
    //pEnt->setMaterialName("2 - Default");
    mTestNode[1]->attachObject( pEnt );
    mTestNode[1]->translate(0,-100,0);

    Quaternion quat2;
    quat2.FromAngleAxis(Degree(360), Vector3::UNIT_Y);

    pEnt = mSceneMgr->createEntity( "3", "knot.mesh" );
    mTestNode[2] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-200, 0, -200));
    mTestNode[2]->attachObject( pEnt );

    createRandomEntityClones(pEnt, 20, Vector3(-1000,0,-1000), Vector3(1000,0,1000), mSceneMgr);


    // Transparent object (can force cast shadows)
    pEnt = mSceneMgr->createEntity( "3.5", "knot.mesh" );
    mTestNode[3] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(350, 0, -200));
    mTestNode[3]->attachObject( pEnt );

    pEnt = mSceneMgr->createEntity( "4", "knot.mesh" );
    mTestNode[2] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(100, 0, 200));
    mTestNode[2]->attachObject( pEnt );

    mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");


    MovablePlane movablePlane(Vector3::UNIT_Y, 100);
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, movablePlane,
                                            2500,2500,10,10,true,1,5,5,Vector3::UNIT_Z);
    Entity* pPlaneEnt;
    pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    if (SHADOWTYPE_TEXTURE_ADDITIVE & SHADOWDETAILTYPE_INTEGRATED)
    {
        pPlaneEnt->setMaterialName("Examples/Plane/IntegratedShadows");
    }
    else
    {
        pPlaneEnt->setMaterialName("2 - Default");
    }
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    addTextureShadowDebugOverlay(1,mSceneMgr);


    /*
      ParticleSystem* pSys2 = mSceneMgr->createParticleSystem("smoke",
      "Examples/Smoke");
      mTestNode[4] = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-300, -100, 200));
      mTestNode[4]->attachObject(pSys2);
    */

    mCameraNode->setPosition(0, 1000, 500);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);
    mCamera->setFarClipDistance(10000);


}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_TextureShadowsCustomCasterMat::PlayPen_TextureShadowsCustomCasterMat()
{
    mInfo["Title"] = "PlayPen_TextureShadowsCustomCasterMat";
    mInfo["Description"] = "Tests texture shadows with a custom caster material.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_TextureShadowsCustomCasterMat::setupContent()
{
    PlayPen_TextureShadows::setupContent();

    MaterialPtr mat = MaterialManager::getSingleton().create("CustomShadowCaster",
                                                             TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setDiffuse(ColourValue::Black);
    p->setEmissive(1, 1, 0);

    mSceneMgr->setShadowTextureCasterMaterial(mat);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_TextureShadowsCustomReceiverMat::PlayPen_TextureShadowsCustomReceiverMat()
{
    mInfo["Title"] = "PlayPen_TextureShadowsCustomReceiverMat";
    mInfo["Description"] = "Tests texture shadows with a custom receiver material.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_TextureShadowsCustomReceiverMat::setupContent()
{
    PlayPen_TextureShadows::setupContent();

    auto mat = MaterialManager::getSingleton().create("CustomShadowReceiver", TRANSIENT_RESOURCE_GROUP);
    Pass* p = mat->getTechnique(0)->getPass(0);
    p->setLightingEnabled(false);
    auto tus = p->createTextureUnitState(); // shadow texture will populate
    tus->setColourOperationEx(LBX_MODULATE, LBS_MANUAL, LBS_TEXTURE, ColourValue(1, 0, 1));
    tus->setProjectiveTexturing(true);

    mSceneMgr->setShadowTextureReceiverMaterial(mat);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_TextureShadowsIntegrated::PlayPen_TextureShadowsIntegrated()
{
    mInfo["Title"] = "PlayPen_TextureShadowsIntegrated";
    mInfo["Description"] = "Tests integrated texture shadows.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_TextureShadowsIntegrated::cleanupContent()
{
    clearDebugTextureOverlays();
}
//----------------------------------------------------------------------------

void PlayPen_TextureShadowsIntegrated::setupContent()
{
    mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_ADDITIVE_INTEGRATED);

    mSceneMgr->setShadowTextureSettings(1024, 2);

    mSceneMgr->setAmbientLight(ColourValue::Black);
    Light* l = mSceneMgr->createLight("Spot1");
    l->setType(Light::LT_SPOTLIGHT);
    l->setAttenuation(5000,1,0,0);
    l->setSpotlightRange(Degree(30),Degree(45),1.0f);
    SceneNode* lightNode1 = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    lightNode1->attachObject(l);
    lightNode1->setPosition(400, 250, 500);
    lightNode1->lookAt(Vector3(0,-200,0), Node::TS_WORLD);
    l->setDiffuseColour(0.7, 0.7, 0.5);

    l = mSceneMgr->createLight("Spot2");
    l->setAttenuation(5000,1,0,0);
    /* // spotlight */
    l->setType(Light::LT_SPOTLIGHT);
    l->setSpotlightRange(Degree(30),Degree(45),1.0f);
    /**/
    // point
    SceneNode* lightNode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    lightNode2->attachObject(l);
    lightNode2->setPosition(-500, 200, 500);
    lightNode2->lookAt(Vector3(0,-200,0), Node::TS_WORLD);
    /* // directional
       l->setType(Light::LT_DIRECTIONAL);
       Vector3 dir(0.5, -1, 0.5);
       dir.normalise();
       l->setDirection(dir);
    */
    l->setDiffuseColour(1, 0.2, 0.2);

    /*
    // Test spot 3
    l = mSceneMgr->createLight("Spot3");
    l->setType(Light::LT_SPOTLIGHT);
    l->setAttenuation(5000,1,0,0);
    l->setSpotlightRange(Degree(30),Degree(45),1.0f);
    SceneNode* lightNode3 = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    lightNode3->attachObject(l);
    lightNode3->setPosition(700, 250, 500);
    lightNode3->lookAt(Vector3(0,-200,0), Node::TS_WORLD);
    l->setDiffuseColour(0.0, 0.7, 1.0);
    */

    // Create a basic plane to have something in the scene to look at
    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 100;
    MeshPtr msh = MeshManager::getSingleton().createPlane("Myplane_IS",
                                                          TRANSIENT_RESOURCE_GROUP, plane,
                                                          4500,4500,100,100,true,1,40,40,Vector3::UNIT_Z);
    msh->buildTangentVectors();
    Entity* pPlaneEnt;
    pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane_IS" );
    //pPlaneEnt->setMaterialName("Examples/OffsetMapping/Specular");
    pPlaneEnt->setMaterialName("Examples/OffsetMapping/IntegratedShadows");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    pPlaneEnt = mSceneMgr->createEntity( "plane2", "Myplane_IS" );
    //pPlaneEnt->setMaterialName("Examples/OffsetMapping/Specular");
    pPlaneEnt->setMaterialName("Examples/OffsetMapping/IntegratedShadows");
    pPlaneEnt->setCastShadows(false);
    SceneNode* n = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    n->roll(Degree(90));
    n->translate(100,0,0);
    //n->attachObject(pPlaneEnt);

    pPlaneEnt = mSceneMgr->createEntity( "plane3", "Myplane_IS" );
    //pPlaneEnt->setMaterialName("Examples/OffsetMapping/Specular");
    pPlaneEnt->setMaterialName("Examples/OffsetMapping/IntegratedShadows");
    pPlaneEnt->setCastShadows(false);
    n = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    n->pitch(Degree(90));
    n->yaw(Degree(-90));
    n->translate(0,0,-100);
    n->attachObject(pPlaneEnt);

    mCameraNode->setPosition(-50, 500, 1000);
    mCameraNode->lookAt(Vector3(Vector3(-50, -100, 0)), Node::TS_PARENT);

    Entity* ent = mSceneMgr->createEntity("athene", "athene.mesh");
    ent->setMaterialName("Examples/Athene/NormalMapped");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,-20,0))->attachObject(ent);

    addTextureShadowDebugOverlay(2, mSceneMgr);



}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_TextureShadowsIntegratedPSSM::PlayPen_TextureShadowsIntegratedPSSM()
{
    mInfo["Title"] = "PlayPen_TextureShadowsIntegratedPSSM";
    mInfo["Description"] = "Tests integrated parallel split shadow mapping.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_TextureShadowsIntegratedPSSM::cleanupContent()
{
    clearDebugTextureOverlays();
}
//----------------------------------------------------------------------------

void PlayPen_TextureShadowsIntegratedPSSM::setupContent()
{
    mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE_INTEGRATED);

    // 3 textures per directional light
    mSceneMgr->setShadowTextureCountPerLightType(Ogre::Light::LT_DIRECTIONAL, 3);
    mSceneMgr->setShadowTextureSettings(512, 3, PF_FLOAT32_R);
    mSceneMgr->setShadowTextureSelfShadow(true);
    // Set up caster material - this is just a standard depth/shadow map caster
    mSceneMgr->setShadowTextureCasterMaterial(
        MaterialManager::getSingleton().getByName("PSSM/shadow_caster", "General"));

    mSceneMgr->setShadowFarDistance(5000);
    mCamera->setFarClipDistance(5000);

    // shadow camera setup
    PSSMShadowCameraSetup* pssmSetup = new PSSMShadowCameraSetup();
    pssmSetup->calculateSplitPoints(3, 250, mCamera->getFarClipDistance());
    pssmSetup->setSplitPadding(80);
    pssmSetup->setOptimalAdjustFactor(0, 2);
    pssmSetup->setOptimalAdjustFactor(1, 1);
    pssmSetup->setOptimalAdjustFactor(2, 0.5);

    mSceneMgr->setShadowCameraSetup(ShadowCameraSetupPtr(pssmSetup));


    mSceneMgr->setAmbientLight(ColourValue(0.3, 0.3, 0.3));
    OrientedLightPtr l = mSceneMgr->createLight("Dir");
    l->setType(Light::LT_DIRECTIONAL);
    Vector3 dir(0.3, -1, 0.2);
    dir.normalise();
    l->setDirection(dir);


    // Create a basic plane to have something in the scene to look at
    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 100;
    MeshPtr msh = MeshManager::getSingleton().createPlane("Myplane",
                                                          TRANSIENT_RESOURCE_GROUP, plane,
                                                          4500,4500,100,100,true,1,40,40,Vector3::UNIT_Z);
    msh->buildTangentVectors();
    Entity* pPlaneEnt;
    pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("Examples/BumpyMetal");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

    mCameraNode->setPosition(-50, 500, 1000);
    mCameraNode->lookAt(Vector3(Vector3(-50, -100, 0)), Node::TS_PARENT);

    Entity* ent = mSceneMgr->createEntity("knot", "knot.mesh");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,0,0))->attachObject(ent);
    createRandomEntityClones(ent, 20, Vector3(-1000,0,-1000), Vector3(1000,0,1000), mSceneMgr);

#ifdef OGRE_BUILD_COMPONENT_RTSHADERSYSTEM
    // Make this viewport work with shader generator scheme.
    mViewport->setMaterialScheme(MSN_SHADERGEN);
    RTShader::ShaderGenerator& rtShaderGen = RTShader::ShaderGenerator::getSingleton();
    RTShader::RenderState* schemRenderState = rtShaderGen.getRenderState(MSN_SHADERGEN);
    auto subRenderState = rtShaderGen.createSubRenderState(RTShader::SRS_SHADOW_MAPPING);
    subRenderState->setParameter("split_points", pssmSetup->getSplitPoints());
    schemRenderState->addTemplateSubRenderState(subRenderState);
#endif

    addTextureShadowDebugOverlay(3, mSceneMgr);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_TextureShadowsTransparentCaster::PlayPen_TextureShadowsTransparentCaster()
{
    mInfo["Title"] = "PlayPen_TextureShadowsTransparentCaster";
    mInfo["Description"] = "Tests transparent shadow casters.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_TextureShadowsTransparentCaster::setupContent()
{
    mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE);
    mSceneMgr->setShadowCameraSetup(FocusedShadowCameraSetup::create());
    mSceneMgr->setShadowTextureSettings(1024, 1, PF_L8);

    // New depth shadow mapping
    String CUSTOM_ROCKWALL_MATERIAL("Examples/Rockwall");

    mSceneMgr->setShadowDirLightTextureOffset(0.2);
    mSceneMgr->setShadowFarDistance(500);

    // Create a basic plane to have something in the scene to look at
    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 100;
    MeshPtr msh = MeshManager::getSingleton().createPlane("Myplane",
                                                          TRANSIENT_RESOURCE_GROUP, plane,
                                                          4500,4500,100,100,true,1,40,40,Vector3::UNIT_Z);
    Entity* pPlaneEnt;
    pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );

    pPlaneEnt->setMaterialName(CUSTOM_ROCKWALL_MATERIAL);
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);



    // Reorient the plane and create a plane mesh for the test planes
    plane.normal = Vector3::UNIT_X;
    MeshManager::getSingleton().createPlane("Test_Plane", TRANSIENT_RESOURCE_GROUP, plane, 50.0, 50.0);

    const String GRASSMAT("Examples/GrassBlades");

    // Add test plane entities to the scene
    Entity* entity = mSceneMgr->createEntity("GrassBlades0", "Test_Plane");
    entity->setMaterialName(GRASSMAT);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(
        Vector3(0.0, -100.0+25.0, 0.0))->attachObject(entity);

    entity = mSceneMgr->createEntity("GrassBlades1", "Test_Plane");
    entity->setMaterialName(GRASSMAT);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(
        Vector3(0.0, -100.0+25.0, -20.0))->attachObject(entity);

    entity = mSceneMgr->createEntity("GrassBlades2", "Test_Plane");
    entity->setMaterialName(GRASSMAT);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(
        Vector3(0.0, -100.0+25.0, -40.0))->attachObject(entity);

    // Add test plane entities to the scene, shadowed partially by athene mesh
    entity = mSceneMgr->createEntity("GrassBlades3", "Test_Plane");
    entity->setMaterialName(GRASSMAT);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(
        Vector3(-80.0, -100.0+25.0, 0.0))->attachObject(entity);

    entity = mSceneMgr->createEntity("GrassBlades4", "Test_Plane");
    entity->setMaterialName(GRASSMAT);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(
        Vector3(-130.0, -100.0+25.0, -20.0))->attachObject(entity);

    entity = mSceneMgr->createEntity("GrassBlades5", "Test_Plane");
    entity->setMaterialName(GRASSMAT);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(
        Vector3(-180.0, -100.0+25.0, -40.0))->attachObject(entity);

    // Add test plane entities to the scene, one after another
    entity = mSceneMgr->createEntity("GrassBlades6", "Test_Plane");
    entity->setMaterialName(GRASSMAT);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(
        Vector3(-260.0, -100.0+25.0, 0.0))->attachObject(entity);

    entity = mSceneMgr->createEntity("GrassBlades7", "Test_Plane");
    entity->setMaterialName(GRASSMAT);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(
        Vector3(-260.0, -100.0+25.0, -10.0))->attachObject(entity);

    entity = mSceneMgr->createEntity("GrassBlades8", "Test_Plane");
    entity->setMaterialName(GRASSMAT);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(
        Vector3(-260.0, -100.0+25.0, -20.0))->attachObject(entity);

    // Add test plane entities to the scene, alone with other material

    const String GRASSMAT_CUSTOM_DEFAULT_CUSTOM("Examples/GrassBlades");
    const String GRASSMAT_CUSTOM_NOSPECIAL_CUSTOM("Examples/GrassBlades");
    const String GRASSMAT_ORIG("Examples/GrassBlades");

    entity = mSceneMgr->createEntity("GrassBlades9", "Test_Plane");
    entity->setMaterialName(GRASSMAT_CUSTOM_DEFAULT_CUSTOM);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(
        Vector3(-80.0, -100.0+25.0, -80.0))->attachObject(entity);

    entity = mSceneMgr->createEntity("GrassBlades10", "Test_Plane");
    entity->setMaterialName(GRASSMAT_CUSTOM_NOSPECIAL_CUSTOM);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(
        Vector3(-130.0, -100.0+25.0, -90.0))->attachObject(entity);

    entity = mSceneMgr->createEntity("GrassBlades11", "Test_Plane");
    entity->setMaterialName(GRASSMAT_ORIG);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(
        Vector3(-180.0, -100.0+25.0, -90.0))->attachObject(entity);

    Entity* ent = mSceneMgr->createEntity("athene", "athene.mesh");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,-20,-20))->attachObject(ent);

    // Position and orient the camera
    mCameraNode->setPosition(100,50,150);
    mCameraNode->lookAt(Vector3(-50, -25, 0), Node::TS_PARENT);

    OrientedLightPtr l = mSceneMgr->createLight("Dir1");
    l->setType(Light::LT_DIRECTIONAL);
    Vector3 dir1(-2.5, -0.7, -0.5);
    dir1.normalise();
    l->setDirection(dir1);
    l->setDiffuseColour(1.0, 1.0, 1.0);

    mSceneMgr->setAmbientLight(ColourValue(0.0, 0.0, 0.2));

    //addTextureShadowDebugOverlay(1, mSceneMgr);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_TransparencyMipMaps::PlayPen_TransparencyMipMaps()
{
    mInfo["Title"] = "PlayPen_TransparencyMipMaps";
    mInfo["Description"] = "Tests transparent materials with mipmaps.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_TransparencyMipMaps::setupContent()
{
    MaterialPtr mat = MaterialManager::getSingleton().create("test",
                                                             TRANSIENT_RESOURCE_GROUP);
    // known png with alpha
    Pass* pass = mat->getTechnique(0)->getPass(0);
    pass->createTextureUnitState("sdk_logo.png");
    pass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
    // alpha blend
    pass->setDepthWriteEnabled(false);

    // alpha reject
    //pass->setDepthWriteEnabled(true);
    //pass->setAlphaRejectSettings(CMPF_LESS, 128);

    // Define a floor plane mesh
    Plane p;
    p.normal = Vector3::UNIT_Y;
    p.d = 200;
    MeshManager::getSingleton().createPlane("FloorPlane",
                                            TRANSIENT_RESOURCE_GROUP,
                                            p,2000,2000,1,1,true,1,5,5,Vector3::UNIT_Z);

    // Create an entity (the floor)
    Entity* ent = mSceneMgr->createEntity("floor", "FloorPlane");
    ent->setMaterialName("test");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);

    mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);
    mSceneMgr->setAmbientLight(ColourValue::White);


    {

        Real alphaLevel = 0.5f;
        MaterialPtr alphamat = MaterialManager::getSingleton().create("testy",
                                                                      TRANSIENT_RESOURCE_GROUP);
        Pass* alphaPass = alphamat->getTechnique(0)->getPass(0);
        alphaPass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
        alphaPass->setDepthWriteEnabled(false);
        TextureUnitState* t = alphaPass->createTextureUnitState();
        t->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, alphaLevel);

        ent = mSceneMgr->createEntity("asd", "ogrehead.mesh");
        ent->setMaterialName("testy");
        mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);

    }

    mCameraNode->setPosition(0,0,1000);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_VertexTexture::PlayPen_VertexTexture()
{
    mInfo["Title"] = "PlayPen_VertexTexture";
    mInfo["Description"] = "Tests vertex texture rendering (DX only).";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_VertexTexture::setupContent()
{
    Light* l = mSceneMgr->createLight("MainLight");
    l->setType(Light::LT_POINT);
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0, 200, 0))->attachObject(l);


    // Create single-channel floating point texture, no mips
    TexturePtr tex = TextureManager::getSingleton().createManual(
        "vertexTexture", TRANSIENT_RESOURCE_GROUP, TEX_TYPE_2D,
        128, 128, 0, PF_FLOAT32_R);
    float* pData = static_cast<float*>(
        tex->getBuffer()->lock(HardwareBuffer::HBL_DISCARD));
    // write concentric circles into the texture
    for (int y  = -64; y < 64; ++y)
    {
        for (int x = -64; x < 64; ++x)
        {

            float val = Math::Sqrt(x*x + y*y);
            // repeat every 20 pixels
            val = val * Math::TWO_PI / 20.0f;
            *pData++ = Math::Sin(val);
        }
    }
    tex->getBuffer()->unlock();

    auto lang = GpuProgramManager::getSingleton().isSyntaxSupported("glsl") ? "glsl" : "hlsl";

    String progSource =
        "#include <OgreUnifiedShader.h>\n"
        "SAMPLER2D(heightmap, 1);\n"
        "uniform mat4 world;\n"
        "uniform mat4 viewProj;\n"
        "uniform float heightscale;\n"
        "MAIN_PARAMETERS\n"
        "IN(vec4 pos , POSITION)\n"
        "IN(vec2 uv0 , TEXCOORD0)\n"
        "OUT(vec2 uv , TEXCOORD0)\n"
        "OUT(vec4 colour , COLOR)\n"
        "MAIN_DECLARATION\n"
        "{\n"
        "gl_Position = mul(world, pos);\n"
        // tex2Dlod since no mip
        "float height = texture2DLod(heightmap, uv0, 0.0).r;\n"
        "gl_Position.y += (height * heightscale);\n"
        "gl_Position = mul(viewProj, gl_Position);\n"
        "uv = uv0;\n"
        "colour = vec4(1,1,1,1);\n"
        "}\n";
    HighLevelGpuProgramPtr prog = HighLevelGpuProgramManager::getSingleton().createProgram(
        "TestVertexTextureFetch", TRANSIENT_RESOURCE_GROUP,
        lang, GPT_VERTEX_PROGRAM);
    prog->setSource(progSource);
    prog->setParameter("target", "vs_3_0");
    prog->setVertexTextureFetchRequired(true);
    prog->load();


    MaterialPtr mat = MaterialManager::getSingleton().create("TestVertexTexture",
                                                             TRANSIENT_RESOURCE_GROUP);
    Pass* pass = mat->getTechnique(0)->getPass(0);
    pass->setLightingEnabled(false);
    pass->setVertexProgram("TestVertexTextureFetch");
    pass->setFragmentProgram("Ogre/BasicFragmentPrograms/DiffuseOneTexture");
    GpuProgramParametersSharedPtr vp = pass->getVertexProgramParameters();
    vp->setNamedAutoConstant("world", GpuProgramParameters::ACT_WORLD_MATRIX);
    vp->setNamedAutoConstant("viewProj", GpuProgramParameters::ACT_VIEWPROJ_MATRIX);
    vp->setNamedConstant("heightscale", 30.0f);

    if(prog->getSyntaxCode() == "glsl")
        vp->setNamedConstant("heightmap", 1);
    // regular texture
    pass->createTextureUnitState("BumpyMetal.jpg");
    // vertex texture
    pass->createTextureUnitState("vertexTexture");

    Plane plane;
    plane.normal = Vector3::UNIT_Y;
    plane.d = 100;
    // 128 x 128 segment plane
    MeshManager::getSingleton().createPlane("Myplane",
                                            TRANSIENT_RESOURCE_GROUP, plane,
                                            1500,1500,128,128,true,1,1,1,Vector3::UNIT_Z);
    Entity* pPlaneEnt;
    pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
    pPlaneEnt->setMaterialName("TestVertexTexture");
    pPlaneEnt->setCastShadows(false);
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);


}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_ViewportNoShadows::PlayPen_ViewportNoShadows()
{
    mInfo["Title"] = "PlayPen_ViewportNoShadows";
    mInfo["Description"] = "Tests disabling shadows for a viewport.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_ViewportNoShadows::setupContent()
{
    mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE);

    // Setup lighting
    mSceneMgr->setAmbientLight(ColourValue(0.2, 0.2, 0.2));
    OrientedLightPtr light = mSceneMgr->createLight("MainLight");
    light->setType(Light::LT_DIRECTIONAL);
    Vector3 dir(-1, -1, 0.5);
    dir.normalise();
    light->setDirection(dir);

    // Create a skydome
    //mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);

    // Create a floor plane mesh
    Plane plane(Vector3::UNIT_Y, 0.0);
    MeshManager::getSingleton().createPlane(
        "FloorPlane", TRANSIENT_RESOURCE_GROUP,
        plane, 200000, 200000, 20, 20, true, 1, 500, 500, Vector3::UNIT_Z);


    // Add a floor to the scene
    Entity* entity = mSceneMgr->createEntity("floor", "FloorPlane");
    entity->setMaterialName("Examples/RustySteel");
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(entity);
    entity->setCastShadows(false);

    // Add the mandatory ogre head
    entity = mSceneMgr->createEntity("head", "ogrehead.mesh");
    mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0.0, 10.0, 0.0))->attachObject(entity);

    // Position and orient the camera
    mCameraNode->setPosition(-100.0, 50.0, 90.0);
    mCameraNode->lookAt(Vector3(0.0, 10.0, -35.0), Node::TS_WORLD);

    // Add an additional viewport on top of the other one
    Viewport* pip = mWindow->addViewport(mCamera, 1, 0.7, 0.0, 0.3, 0.3);
    pip->setShadowsEnabled(false);

}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

PlayPen_WindowedViewportMode::PlayPen_WindowedViewportMode()
{
    mInfo["Title"] = "PlayPen_WindowedViewportMode";
    mInfo["Description"] = "Tests windowed viewport.";
    addScreenshotFrame(10);
}
//----------------------------------------------------------------------------

void PlayPen_WindowedViewportMode::setupContent()
{
    Ogre::SceneNode* mTestNode[5];

    // Set ambient light
    mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

    // Create a point light
    OrientedLightPtr l = mSceneMgr->createLight("MainLight");
    l->setType(Light::LT_DIRECTIONAL);
    l->setDirection(-Vector3::UNIT_Y);

    mTestNode[0] = (SceneNode*)mSceneMgr->getRootSceneNode()->createChild();

    Entity* pEnt = mSceneMgr->createEntity( "1", "ogrehead.mesh" );
    mTestNode[0]->attachObject( pEnt );

    mWindow->update(false);
    auto rsys = Root::getSingleton().getRenderSystem();
    rsys->_setRenderTarget(mWindow);
    rsys->setScissorTest(true, Rect(0, 0, mWindow->getWidth() * 0.5, mWindow->getHeight() * 0.5));

    mCameraNode->setPosition(0,0,125);
}

void PlayPen_WindowedViewportMode::unloadResources()
{
    Root::getSingleton().getRenderSystem()->setScissorTest(false);
}

PlayPen_BillboardText::PlayPen_BillboardText()
{
    mInfo["Title"] = "PlayPen_BillboardText";
    mInfo["Description"] = "Tests setting billboard text";
    addScreenshotFrame(1);
}
//----------------------------------------------------------------------------

void PlayPen_BillboardText::setupContent()
{
    BillboardSet* bbs = mSceneMgr->createBillboardSet();

    auto font = FontManager::getSingleton().getByName("DejaVu/SerifCondensedItalic", "Tests");

    font->putText(bbs, "Jörg bäckt quasi\nzwei Haxenfüße vom", 10);
    font->putText(bbs, "Wildpony", 15, ColourValue::Blue);

    mSceneMgr->getRootSceneNode()
        ->createChildSceneNode(bbs->getBoundingBox().getHalfSize()*Vector3(-1, 1, 0))
        ->attachObject(bbs);

    mCameraNode->setPosition(0,0,160);
    mCameraNode->lookAt(Vector3(0, 0, 0), Node::TS_PARENT);
}


PlayPen_PBR::PlayPen_PBR()
{
    mInfo["Title"] = "PlayPen_PBR";
    mInfo["Description"] = "Tests PBR";
    mInfo["Category"] = "Tests";
    mInfo["Thumbnail"] = "thumb_visual_tests.png";
    addScreenshotFrame(1);
}
//----------------------------------------------------------------------------

void PlayPen_PBR::setupContent()
{
    // Make this viewport work with shader generator scheme.
    mViewport->setMaterialScheme(MSN_SHADERGEN);

    mCamera->setNearClipDistance(0.5f);

    auto plane = MeshManager::getSingleton().createPlane("Plane", TRANSIENT_RESOURCE_GROUP, Plane(Vector3::UNIT_Y, 1),
                                                         50, 50, 1, 1, true, 1, 8, 8, Vector3::UNIT_Z);

    // build tangent vectors for our mesh
    plane->buildTangentVectors();

    auto ground = mSceneMgr->createEntity("Plane");
    ground->setMaterialName("Examples/WoodenFloor");
    mSceneMgr->getRootSceneNode()->attachObject(ground);

    Ogre::Light* light = mSceneMgr->createLight();
    Ogre::SceneNode* lightNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    lightNode->attachObject(light);
    light->setType(Light::LT_DIRECTIONAL);
    lightNode->setDirection(Vector3(-1, -1, -1).normalisedCopy());

    mSceneMgr->setAmbientLight(ColourValue(0.6f, 0.45f, 0.3f) * 0.065f * 0.75f);

    light = mSceneMgr->createLight();
    lightNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    lightNode->attachObject(light);
    light->setDiffuseColour(0.8f, 0.4f, 0.2f); // Warm
    light->setType(Light::LT_SPOTLIGHT);
    light->setPowerScale(Math::PI);
    lightNode->setPosition(-10.0f, 10.0f, 10.0f);
    lightNode->setDirection(Vector3(1, -1, -1).normalisedCopy());
    light->setAttenuation(100, 0.5, 0, 0.5/100);

    light = mSceneMgr->createLight();
    lightNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    lightNode->attachObject(light);
    light->setDiffuseColour(0.2f, 0.4f, 0.8f); // Cold
    light->setType(Light::LT_SPOTLIGHT);
    light->setPowerScale(Math::PI);
    lightNode->setPosition(10.0f, 10.0f, -10.0f);
    lightNode->setDirection(Vector3(-1, -1, 1).normalisedCopy());
    light->setAttenuation(100, 0.5, 0, 0.5/100);

    auto baseMat = MaterialManager::getSingleton().getByName("Examples/PBR_Sphere");

    const float armsLength = 2.5f;
    for (int i = 0; i < 4; ++i)
    {
        for (int j = 0; j < 4; ++j)
        {
            auto sphere = mSceneMgr->createEntity("Sphere1000.mesh");
            sphere->setMaterial(MaterialManager::getSingleton().getDefaultMaterial(true));
            auto node = mSceneMgr->getRootSceneNode()->createChildSceneNode();

            node->setPosition((i - 1.5f) * armsLength, 2.0f, (j - 1.5f) * armsLength);
            node->setScale(0.65f, 0.65f, 0.65f);
            node->attachObject(sphere);

            int idx = i * 4 + j;
            auto mat =
                baseMat->clone(StringUtil::format("Examples/PBR_Sphere%d", idx), String(TRANSIENT_RESOURCE_GROUP));
#ifdef OGRE_BUILD_COMPONENT_RTSHADERSYSTEM
            RTShader::ShaderGenerator::getSingleton().cloneShaderBasedTechniques(*baseMat, *mat);
#endif
            ColourValue spec;
            spec[0] = i / 3.0; // metal
            spec[1] = j / 3.0; // roughness
            mat->setSpecular(spec);
            sphere->setMaterial(mat);
        }
    }

    mCameraNode->setPosition(0, -5, 10);
    mCameraNode->lookAt(Vector3::ZERO, Node::TS_PARENT);

    if(!mCameraMan)
        return;

    mCameraMan->setStyle(OgreBites::CS_ORBIT);
}
void PlayPen_PBR::unloadResources()
{
    ResourceGroupManager::getSingleton().clearResourceGroup(TRANSIENT_RESOURCE_GROUP);
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------

void addTextureDebugOverlay(const Ogre::String& texname, size_t i)
{
    Ogre::Overlay* debugOverlay = Ogre::OverlayManager::getSingleton().getByName("Core/DebugOverlay");

    if(!debugOverlay)
        debugOverlay = Ogre::OverlayManager::getSingleton().create("Core/DebugOverlay");

    debugOverlay->show();

    // Set up a debug panel to display the shadow
    Ogre::MaterialPtr debugMat = Ogre::MaterialManager::getSingleton().create(
        "Ogre/DebugTexture" + Ogre::StringConverter::toString(i),
        "VisualTestTransient");
    debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false);
    debugMat->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false);
    Ogre::TextureUnitState *t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(texname);
    t->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);

    Ogre::OverlayContainer* debugPanel = (Ogre::OverlayContainer*)
        (Ogre::OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/DebugTexPanel" + Ogre::StringConverter::toString(i)));
    debugPanel->_setPosition(0.8, i*0.25);
    debugPanel->_setDimensions(0.2, 0.24);
    debugPanel->setMaterial(debugMat);
    debugOverlay->add2D(debugPanel);

}
//-----------------------------------------------------------------------

void clearDebugTextureOverlays()
{
    Ogre::Overlay* debugOverlay = Ogre::OverlayManager::getSingleton().getByName("Core/DebugOverlay");

    if(debugOverlay)
        Ogre::OverlayManager::getSingleton().destroy("Core/DebugOverlay");
    //debugOverlay->hide();

    for(int i = 0; i < 10; ++i)
    {
        if(Ogre::OverlayManager::getSingleton().hasOverlayElement(
            "Ogre/DebugTexPanel" + Ogre::StringConverter::toString(i)))
        {
            OverlayManager::getSingleton().destroyOverlayElement(
                "Ogre/DebugTexPanel" + Ogre::StringConverter::toString(i));
            MaterialManager::getSingleton().remove("Ogre/DebugTexture" + StringConverter::toString(i), "VisualTestTransient");
        }
    }
}
//-----------------------------------------------------------------------

void addTextureDebugOverlay(const Ogre::TexturePtr& tex, size_t i)
{
    addTextureDebugOverlay(tex->getName(), i);
}
//-----------------------------------------------------------------------

void addTextureShadowDebugOverlay(size_t num, Ogre::SceneManager* mgr)
{
    for (size_t i = 0; i < num; ++i)
    {
        Ogre::TexturePtr shadowTex = mgr->getShadowTexture(i);
        addTextureDebugOverlay(shadowTex, i);
    }
}
//-----------------------------------------------------------------------
